Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • saref/saref-pipeline
1 result
Show changes
Commits on Source (2)
...@@ -27,8 +27,8 @@ package fr.mines_stetienne.ci.saref.checkers; ...@@ -27,8 +27,8 @@ package fr.mines_stetienne.ci.saref.checkers;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.ArrayList;
import java.util.Map; import java.util.List;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -74,8 +74,10 @@ public class Clause_9_4_6_Checker extends AbstractClauseChecker { ...@@ -74,8 +74,10 @@ public class Clause_9_4_6_Checker extends AbstractClauseChecker {
// First get the available directories. If none, not a problem. // First get the available directories. If none, not a problem.
File dir2 = new File(repository.getDirectory(), "patterns"); File dir2 = new File(repository.getDirectory(), "patterns");
String[] directoryList = new String[]{}; List<String> shaclFileList = new ArrayList();
// process every shapes.ttl file in the sub-directories of the patterns directory.
try { try {
String[] directoryList = new String[]{};
String directories = Files.walk(dir2.toPath()).filter(p -> { String directories = Files.walk(dir2.toPath()).filter(p -> {
try { try {
return p.toFile().isDirectory() && !Files.isSameFile(dir2.toPath(), p); return p.toFile().isDirectory() && !Files.isSameFile(dir2.toPath(), p);
...@@ -87,24 +89,22 @@ public class Clause_9_4_6_Checker extends AbstractClauseChecker { ...@@ -87,24 +89,22 @@ public class Clause_9_4_6_Checker extends AbstractClauseChecker {
return; // no SHACL directories found. return; // no SHACL directories found.
} }
directoryList = directories.split(","); directoryList = directories.split(",");
for(int i = 0; i < directoryList.length; i++) {
shaclFileList.add(directoryList[i] + "/shapes.ttl");
}
} catch (IOException e) { } catch (IOException e) {
logError(getMessage(Clause_9_4_6_Checker.MESSAGE.ioexception), e); logError(getMessage(Clause_9_4_6_Checker.MESSAGE.ioexception), e);
} }
ShaclValidationManager.PingValidationServer(); ShaclValidationManager.PingValidationServer();
Map<String, HttpResponse<String>> responseMap = new HashMap<String, HttpResponse<String>>(); //Map<String, HttpResponse<String>> responseMap = new HashMap<String, HttpResponse<String>>();
// process every shapes.ttl file in the sub-directories of the patterns directory. try {
for(int i = 0; i < directoryList.length; i++) { ShaclValidationManager shaclValidationManager = new ShaclValidationManager(ontologyToValidate);
String shaclFileName = directoryList[i] + "/shapes.ttl"; // "file://" + HttpResponse<String> response = shaclValidationManager.ValidateOntologyWithShacl(shaclFileList);
try { //responseMap.put(shaclFileName, response); // parse map for errors
HttpResponse<String> response = new ShaclValidationManager(ontologyToValidate).validateOntologyWithShacl(shaclFileName); } catch (IOException | InterruptedException e) {
System.out.println(response); //<<< logError(getMessage(Clause_9_4_6_Checker.MESSAGE.ioexception, ontologyToValidate));
responseMap.put(shaclFileName, response); //<<< parse map for errors
} catch (IOException | InterruptedException e) {
logError(getMessage(Clause_9_4_6_Checker.MESSAGE.ioexception, shaclFileName));
}
} }
//System.out.println(responseMap); //<<<
} }
} }
\ No newline at end of file
...@@ -32,30 +32,34 @@ import java.net.URL; ...@@ -32,30 +32,34 @@ import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.net.http.*; import java.net.http.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.nio.file.Paths;
import java.util.Map; import java.util.Map;
import java.util.Base64; import java.util.List;
import java.util.ArrayList;
//import java.util.HashMap;
import org.apache.commons.lang3.StringEscapeUtils;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import fr.mines_stetienne.ci.saref.SAREFPipelineException; import fr.mines_stetienne.ci.saref.SAREFPipelineException;
/* docker run -d --name SAREFvalidator -p 8080:8080 isaitb/shacl-validator # runs the generic validator. /* docker run -d --name SAREFvalidator -p 8080:8080 isaitb/shacl-validator # runs the generic validator with Dockerfile
Docs for RDF validator: https://www.itb.ec.europa.eu/docs/guides/latest/validatingRDF/index.html Docs for RDF validator: https://www.itb.ec.europa.eu/docs/guides/latest/validatingRDF/index.html
Base docker image: https://hub.docker.com/r/isaitb/shacl-validator (generic validator) Base docker image: https://hub.docker.com/r/isaitb/shacl-validator (generic validator)
Use Swagger UI for testing: http://localhost:8080/shacl/swagger-ui/index.html#/{domain}/api/validate Use Swagger UI for testing: http://localhost:8080/shacl/swagger-ui/index.html#/{domain}/api/validate
BASE64 Encoder/Decoder: https://www.base64encode.org/
* */ * */
public class ShaclValidationManager { public class ShaclValidationManager {
private static String VALIDATOR_URL = "http://localhost:8080/shacl/"; private static String VALIDATOR_URL = "http://localhost:8080/shacl/";
private final String TEXT_TURTLE = "text/turtle";
private final String JSON_FORMAT = "application/json"; // application/x-www-form-urlencoded
private final String STRING_FORMAT = "STRING";
private String ontologyToValidate; // file:///home/davidgnabasik/dev/real_saref4auto/ontology/saref4auto.ttl or URL private String ontologyToValidate; // file:///home/davidgnabasik/dev/real_saref4auto/ontology/saref4auto.ttl or URL
private List<String> shaclFileList;
private List<RuleSet> ruleSetList;
private HttpClient client; private HttpClient client;
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
private ValidationRequest validationRequest;
//private String shaclRequestBody =
// "{ \"contentToValidate\": \"ONTOLOGY_AS_BASE64_STRING\", \"embeddingMethod\": \"BASE64\", \"contentSyntax\": \"text/turtle\", \"reportSyntax\": \"application/json\", \"locale\": \"en\", \"rdfReportSyntax\": \"application/json\", \"externalRules\": [ { \"ruleSet\": \"SHACL_AS_BASE64_STRING\", \"embeddingMethod\": \"BASE64\", \"ruleSyntax\": \"text/turtle\" } ] }";
private static String encodeBody(Object obj) { private static String encodeBody(Object obj) {
return URLEncoder.encode(obj.toString(), StandardCharsets.UTF_8); return URLEncoder.encode(obj.toString(), StandardCharsets.UTF_8);
...@@ -65,12 +69,78 @@ public class ShaclValidationManager { ...@@ -65,12 +69,78 @@ public class ShaclValidationManager {
http_exception, ioexception http_exception, ioexception
} }
class RuleSet {
private String ruleSet; // JSON-encoded_SHACL_shape
public String getRuleSet() {
return ruleSet;
}
public void setRuleSet(String ruleSet) {
this.ruleSet = ruleSet;
}
// constants for now...
public String getEmbeddingMethod() { return STRING_FORMAT; }
public String getRuleSyntax() { return TEXT_TURTLE; }
}
class ValidationRequest {
private String contentToValidate; // JSON-encoded ontology
private List<RuleSet> externalRules;
private Map<String, Object> properties; // needed?
public String getContentToValidate() {
return contentToValidate;
}
public void setContentToValidate(String contentToValidate) {
this.contentToValidate = contentToValidate;
}
public Map<String, Object> getProperties() {
return properties;
}
public void setProperties(Map<String, Object> properties) {
this.properties = properties;
}
// constants for now...
public String getEmbeddingMethod() {
return STRING_FORMAT;
}
public String getContentSyntax() {
return TEXT_TURTLE;
}
public String getReportSyntax() {
return JSON_FORMAT;
}
public String getRdfReportSyntax() {
return JSON_FORMAT;
}
public String getLocale() {
return "en";
}
public List<RuleSet> getExternalRules() {
return externalRules;
}
public void setExternalRules(List<RuleSet> externalRules) {
this.externalRules = externalRules;
}
}
/** /**
* Open a REST interface to the SHACL validator. * Open a REST interface to the SHACL validator.
*/ */
public ShaclValidationManager(String ontologyToValidate) throws IOException { public ShaclValidationManager(String ontologyToValidate) throws IOException {
client = HttpClient.newHttpClient(); this.client = HttpClient.newHttpClient();
objectMapper = new ObjectMapper(); this.objectMapper = new ObjectMapper();
this.ontologyToValidate = ontologyToValidate; this.ontologyToValidate = ontologyToValidate;
String url = System.getenv("VALIDATOR_URL"); String url = System.getenv("VALIDATOR_URL");
if (url != null) VALIDATOR_URL = url; if (url != null) VALIDATOR_URL = url;
...@@ -94,19 +164,49 @@ public class ShaclValidationManager { ...@@ -94,19 +164,49 @@ public class ShaclValidationManager {
} }
/** /**
* Preferred validation format is BASE64. Read file; return single BASE64-encoded string. * Read shacl files. Assign this.shaclFileList, this.ruleSetList.
* Preferred validation format is JSON-escaped text. Requires \r\n as line breaks!!!
*/
private void createRuleSetList(List<String> shaclFileList) {
this.shaclFileList = new ArrayList();
this.ruleSetList = new ArrayList();
for (int i = 0; i < shaclFileList.size(); i++) {
String readingFile = shaclFileList.get(i);
try {
String fileStr = new String(Files.readAllBytes(Paths.get(readingFile)));
RuleSet ruleSet = new RuleSet();
ruleSet.setRuleSet(fileStr); //.replaceAll("[\n]","\r\n"));
this.shaclFileList.add(readingFile);
this.ruleSetList.add(ruleSet);
} catch (IOException ex) {
System.out.println("ShaclValidationManager unable to read SHACL file: " + readingFile);
}
}
}
/**
* Assign ValidationRequest object.
* Preferred validation format is JSON-escaped text. Requires \r\n as line breaks!!!
* @throws SAREFPipelineException * @throws SAREFPipelineException
*/ */
public static String FormatAsBase64(String ontologyFile) throws SAREFPipelineException { private void createValidationRequest(List<String> shaclFileList) throws SAREFPipelineException {
createRuleSetList(shaclFileList);
if (this.ruleSetList.size() < 1) {
throw new SAREFPipelineException("ShaclValidationManager", "No SHACL files to process!");
}
// process ontology file
try { try {
String value = Files.readString(Path.of(ontologyFile)); // 2Gb file size limit. String fileStr = new String(Files.readAllBytes(Paths.get(this.ontologyToValidate)));
return Base64.getUrlEncoder().encodeToString(value.getBytes()); this.validationRequest = new ValidationRequest();
this.validationRequest.setContentToValidate(fileStr); // .replaceAll("[\n]","\r\n"));
this.validationRequest.setExternalRules(this.ruleSetList);
} catch (IOException ex) { } catch (IOException ex) {
throw new SAREFPipelineException("FormatAsBase64", "Unable to format file as base64: " + ontologyFile); throw new SAREFPipelineException("ShaclValidationManager", "Unable to read ontology file: " + this.ontologyToValidate);
} }
} }
public static HttpRequest.BodyPublisher ofForm(Map<String, Object> data) { private HttpRequest.BodyPublisher ofForm(Map<String, Object> data) {
StringBuilder body = new StringBuilder(); StringBuilder body = new StringBuilder();
for (Object dataKey : data.keySet()) { for (Object dataKey : data.keySet()) {
if (body.length() > 0) { if (body.length() > 0) {
...@@ -121,46 +221,30 @@ public class ShaclValidationManager { ...@@ -121,46 +221,30 @@ public class ShaclValidationManager {
/** /**
* POST JSON response format: * POST JSON response format:
{ LIST OF: @prefix : <https://saref.etsi.org/saref4auto/> .
"date": "2024-04-05T10:18:24.197+0000", [ rdf:type sh:ValidationReport ;
"result": "SUCCESS", sh:conforms true
"overview": { ] .
"profileID": "Clause_9_4_3_1" * Generic validator option: 1. Replace {contentToValidate} value with the ontology to validate encoded in JSON. This can also be done with URLs.
}, * 2. Configure the user-provided SHACL shape as a RuleSet element of the externalRules array.
"counters": { * [ "ruleSet": "JSON-encoded_SHACL_shape", "embeddingMethod":"STRING", "ruleSyntax": TEXT_TURTLE ]
"nrOfAssertions": 0, * POST request to Validate a single RDF ontology.
"nrOfErrors": 0, * @throws SAREFPipelineException
"nrOfWarnings": 0
},
"context": {},
"reports": {},
"name": "SHACL Validation"
}
* Generic validator option: 1. Replace {contentToValidate} value with the ontology to validate encoded in BASE64. (This can aos be done with URLs.)
* 2. Configure the user-provided SHACL shape as a RuleSet element of the externalRules array. The content of each RuleSet is as follows:
* [ "ruleSet": "BASE64-encoded_SHACL_shape", "embeddingMethod":"BASE64", "ruleSyntax": "text/turtle" ] We run one SHACL shape at a time.
* POST request to Validate a single RDF instance.
* @throws IOException * @throws IOException
* @throws InterruptedException * @throws InterruptedException
*/ */
public HttpResponse<String> validateOntologyWithShacl(String shaclFile) throws SAREFPipelineException, InterruptedException { public HttpResponse<String> ValidateOntologyWithShacl(List<String> shaclFileList) throws SAREFPipelineException, InterruptedException {
try { try {
String ontologyBase64String = FormatAsBase64(this.ontologyToValidate); createValidationRequest(shaclFileList);
String shaclBase64String = FormatAsBase64(shaclFile);
// populate shaclRequestBody json struct to map (no TypeReference) String jsonStr = this.objectMapper.writeValueAsString(this.validationRequest);
String shaclRequestBody = "{ \"contentToValidate\": \"" + ontologyBase64String + String escapedJson = StringEscapeUtils.escapeJson(jsonStr);
"\", \"embeddingMethod\": \"BASE64\", \"contentSyntax\": \"text/turtle\", \"reportSyntax\": \"application/json\", \"locale\": \"en\", \"rdfReportSyntax\": \"application/json\", \"externalRules\": [ { \"ruleSet\": \"" + System.out.println(escapedJson);//<<<
shaclBase64String + "\", \"embeddingMethod\": \"BASE64\", \"ruleSyntax\": \"text/turtle\" } ] }";
byte[] mapData = shaclRequestBody.getBytes();
Map<String,Object> myMap = objectMapper.readValue(mapData, HashMap.class);
// now update JSON data
//myMap.put("contentToValidate", ontologyBase64String);
//myMap.put("ruleSet", shaclBase64String);
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.header("Content-Type", "text/turtle") // application/x-www-form-urlencoded .header("Content-Type", JSON_FORMAT)
.uri(URI.create(VALIDATOR_URL + "any/upload")) .uri(URI.create(VALIDATOR_URL + "any/upload")) // any/api/validate
.POST(ofForm(myMap)) .POST(HttpRequest.BodyPublishers.ofString(jsonStr)) // escapedJson
.build(); .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
...@@ -168,7 +252,7 @@ public class ShaclValidationManager { ...@@ -168,7 +252,7 @@ public class ShaclValidationManager {
System.out.println("\n Body: " + response.body()); System.out.println("\n Body: " + response.body());
return response; return response;
} catch (IOException ex) { } catch (IOException ex) {
throw new SAREFPipelineException("validateOntologyWithShacl", "Unable to process SHACL file: " + shaclFile); throw new SAREFPipelineException("ValidateOntologyWithShacl", "Unable to validate ontology: " + this.ontologyToValidate);
} }
} }
......
server_unavailable=The validation server is unavailable at `%s`
ioexception=Error while accessing the local file system
missing=The shacl directory should contain at least one file. This file shall conform to the pattern specification as defined in clause 9.4.6 in TS 103 673.
one=If a shacl directory exists, it should contain at least one shapes.ttl file.