Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

package org.apache.jena.arq.junit.manifest;

import java.util.ArrayList;
import java.util.List;

import org.apache.jena.arq.junit.SurpressedTest;
Expand Down Expand Up @@ -52,7 +53,9 @@ private static TestMakers systemSetup() {
* Add a test maker to the system-wide test makers list
*/
public static void install(TestMaker testMaker) {
systemSetup.add(testMaker);
List<TestMaker> next = new ArrayList<>(systemSetup.installed);
next.add(testMaker);
set(next);
}

public static void reset() {
Expand All @@ -77,10 +80,6 @@ private TestMakers(List<TestMaker> testMakers) {
installed = testMakers;
}

public void add(TestMaker testMaker) {
installed.add(testMaker);
}

public void clear() {
installed.clear();
}
Expand Down
73 changes: 41 additions & 32 deletions jena-cmds/src/main/java/shacl/shacl_validate.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

package shacl;

import java.util.List;

import org.apache.jena.atlas.logging.LogCtl;
import org.apache.jena.cmd.ArgDecl;
import org.apache.jena.cmd.CmdException;
Expand All @@ -36,11 +38,14 @@
import org.apache.jena.shacl.ValidationReport;
import org.apache.jena.shacl.engine.ValidationContext;
import org.apache.jena.shacl.lib.ShLib;
import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.sys.JenaSystem;

/** SHACL validation.
* <p>
* Usage: <code>shacl validate [--text] --shapes SHAPES --data DATA</code>
* <pre>
* Usage: <code>shacl validate [--text] [-v|--verbose] [--target=] --shapes SHAPES --data DATA</code>
* Usage: <code>shacl validate [--text] [-v|--verbose] [--target=] FILE</code>
* </pre>
*/
public class shacl_validate extends CmdMain {

Expand All @@ -55,8 +60,10 @@ public class shacl_validate extends CmdMain {
private ArgDecl argShapes = new ArgDecl(true, "--shapes", "--shapesfile", "--shapefile", "-s");
private ArgDecl argTargetNode = new ArgDecl(true, "--target", "--node", "-n", "-t");

private String datafile = null;
private String shapesfile = null;
// Allow multiple files for each - combine into one graph each for data and for shapes.
private List<String> datafiles = null;
private List<String> shapesfiles = null;
private String shapesURL = null;
private String targetNode = null; // Parse later.
private boolean textOutput = false;

Expand All @@ -75,52 +82,51 @@ public shacl_validate(String[] argv) {

@Override
protected String getSummary() {
return getCommandName()+" [--target URI] --shapes shapesFile --data dataFile";
return getCommandName()+" [--target URI] [--shapes shapesFile --data dataFile] [FILE ...]";
}

@Override
protected void processModulesAndArgs() {
super.processModulesAndArgs();

datafile = super.getValue(argData);
shapesfile = super.getValue(argShapes);
// --data can be empty in which case shapes and data are in the shapes files.
datafiles = super.getValues(argData);
shapesfiles = super.getValues(argShapes);

// No -- arguments, use act on single file of shapes and data.
if ( datafile == null && shapesfile == null ) {
if ( positionals.size() == 1 ) {
datafile = positionals.get(0);
shapesfile = positionals.get(0);
}
// If there are no arguments, act the commandline positional arguments as shapes and data.
if ( datafiles.isEmpty() && shapesfiles.isEmpty() ) {
if ( positionals.isEmpty() )
throw new CmdException("No input");
shapesfiles = positionals;
}

if ( datafile == null )
throw new CmdException("Usage: "+getSummary());
if ( shapesfile == null )
shapesfile = datafile;
if ( shapesfiles == null || shapesfiles.isEmpty() )
throw new CmdException("No shapes files");

textOutput = super.hasArg(argOutputText);

if ( contains(argTargetNode) ) {
if ( contains(argTargetNode) )
targetNode = getValue(argTargetNode);
}

// For imports.
shapesURL = shapesfiles.getFirst();
}

@Override
protected void exec() {
Graph shapesGraph = load(shapesfile, "shapes file");
Graph shapesGraph = load(shapesfiles);
Graph dataGraph;
if ( datafile.equals(shapesfile) )
if ( datafiles.isEmpty() )
dataGraph = shapesGraph;
else
dataGraph = load(datafile, "data file");
dataGraph = load(datafiles);

Node node = null;
if ( targetNode != null ) {
String x = dataGraph.getPrefixMapping().expandPrefix(targetNode);
node = NodeFactory.createURI(x);
}

shapesGraph = Imports.withImports(shapesfile, shapesGraph);
shapesGraph = Imports.withImports(shapesURL, shapesGraph);

if ( isVerbose() )
ValidationContext.VERBOSE = true;
Expand All @@ -138,14 +144,17 @@ protected void exec() {
RDFDataMgr.write(System.out, report.getGraph(), Lang.TTL);
}

private Graph load(String filename, String scope) {
try {
Graph graph = RDFDataMgr.loadGraph(filename);
return graph;
} catch (RiotException ex) {
System.err.println("Loading "+scope);
throw ex;
}
private Graph load(List<String> files) {
Graph graph = GraphFactory.createDefaultGraph();
files.forEach(fn-> {
try {
RDFDataMgr.read(graph, fn);
} catch (RiotException ex) {
System.err.println("Error loading "+fn);
throw ex;
}
});
return graph;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.apache.jena.shacl.engine.constraint;

import java.util.Set;

import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.shacl.engine.ValidationContext;
import org.apache.jena.shacl.parser.Constraint;
import org.apache.jena.shacl.parser.Shape;
import org.apache.jena.shacl.validation.ReportItem;
import org.apache.jena.shacl.validation.event.ConstraintEvaluatedOnFocusNodeEvent;
import org.apache.jena.shacl.validation.event.ConstraintEvaluatedOnSinglePathNodeEvent;
import org.apache.jena.sparql.path.Path;

public abstract class ConstraintList implements Constraint {

protected ConstraintList() {}

@Override
final
public void validatePropertyShape(ValidationContext vCxt, Graph data, Shape shape, Node focusNode, Path path, Set<Node> valueNodes) {
valueNodes.forEach(x->applyConstraintList(vCxt, shape, focusNode, path, data, x));
}

@Override
final
public void validateNodeShape(ValidationContext vCxt, Graph data, Shape shape, Node focusNode) {
applyConstraintList(vCxt, shape, focusNode, null, data, focusNode);
}

private void applyConstraintList(ValidationContext vCxt, Shape shape, Node focusNode, Path path, Graph data, Node listHead) {
ReportItem item = validateList(vCxt, data, listHead);
boolean passed = (item == null);
if (path == null) {
vCxt.notifyValidationListener(() -> new ConstraintEvaluatedOnFocusNodeEvent(vCxt, shape, focusNode, this, passed));
} else {
vCxt.notifyValidationListener(() -> new ConstraintEvaluatedOnSinglePathNodeEvent(vCxt, shape, focusNode, this, path,
listHead, passed));
}
if ( passed )
return;
vCxt.reportEntry(item, shape, focusNode, path, this);
}

protected abstract ReportItem validateList(ValidationContext vCxt, Graph data, Node n) ;
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void validateNodeShape(ValidationContext vCxt, Graph data, Shape shape, N

private void applyConstraintTerm(ValidationContext vCxt, Shape shape, Node focusNode, Path path, Node term) {
ReportItem item = validate(vCxt, term);
boolean passed = item == null;
boolean passed = (item == null);
if (path == null) {
vCxt.notifyValidationListener(() -> new ConstraintEvaluatedOnFocusNodeEvent(vCxt, shape, focusNode, this, passed));
} else {
Expand All @@ -65,5 +65,5 @@ private void applyConstraintTerm(ValidationContext vCxt, Shape shape, Node focus
vCxt.reportEntry(item, shape, focusNode, path, this);
}

public abstract ReportItem validate(ValidationContext vCxt, Node n) ;
protected abstract ReportItem validate(ValidationContext vCxt, Node n) ;
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public RDFDatatype getRDFDatatype() {
}

@Override
public ReportItem validate(ValidationContext vCxt, Node n) {
protected ReportItem validate(ValidationContext vCxt, Node n) {
if ( n.isLiteral() && dtURI.equals(n.getLiteralDatatypeURI()) ) {
// Must be valid for the type
if ( ! rdfDatatype.isValid(n.getLiteralLexicalForm()) ) {
Expand Down Expand Up @@ -131,6 +131,7 @@ public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {

@Override
public String toString() {
// DRY (with ListMmeberShape, others?
String x;
if ( datatype.isURI() ) {
if ( dtURI.startsWith(XSD.getURI()) )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public Node getComponent() {
}

@Override
public ReportItem validate(ValidationContext vCxt, Node n) {
protected ReportItem validate(ValidationContext vCxt, Node n) {
if ( values.contains(n) )
return null;
String errMsg = toString()+" : RDF term "+displayStr(n)+" not in expected values";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public Node getComponent() {
}

@Override
public ReportItem validate(ValidationContext vCxt, Node n) {
protected ReportItem validate(ValidationContext vCxt, Node n) {
String msg = String.format("%s[%s]", message, ShLib.displayStr(n));
ShaclSystem.shaclSystemLogger.warn(msg);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public Node getComponent() {
}

@Override
public ReportItem validate(ValidationContext vCxt, Node n) {
protected ReportItem validate(ValidationContext vCxt, Node n) {
if ( ! generateViolation )
return null;
return new ReportItem("Violation");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

package org.apache.jena.shacl.engine.constraint;

import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.atlas.lib.NotImplemented;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.Node;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.shacl.engine.ValidationContext;
import org.apache.jena.shacl.parser.ConstraintVisitor;
import org.apache.jena.shacl.validation.ReportItem;
import org.apache.jena.shacl.vocabulary.SHACL;

/** sh:memberShape */

public class ListMaxLength extends ConstraintList {

public ListMaxLength(Node node) {}

@Override
public void visit(ConstraintVisitor visitor){
visitor.visit(this);
}

@Override
public void printCompact(IndentedWriter out, NodeFormatter nodeFmt) {
throw new NotImplemented();
}

@Override
protected ReportItem validateList(ValidationContext vCxt, Graph data, Node headNode) {
throw new NotImplemented();
}

@Override
public Node getComponent() {
return SHACL.ListMaxLengthConstraintComponent;
}

@Override
public void print(IndentedWriter out, NodeFormatter nodeFmt) {
out.print(toString());
}

@Override
public String toString() {
return "ListMemberShape[]";
}

@Override
public int hashCode() {
throw new NotImplemented();
}

@Override
public boolean equals(Object obj) {
if ( this == obj )
return true;
if ( obj == null )
return false;
if ( !(obj instanceof ListMaxLength other) )
return false;
throw new NotImplemented();
}

}
Loading