|
19 | 19 | import org.apache.jena.vocabulary.RDFS;
|
20 | 20 | import org.topbraid.shacl.vocabulary.SH;
|
21 | 21 |
|
22 |
| -public class ShapeTargetResolver { |
| 22 | +/** |
| 23 | + * Resolves the target definitions of shapes to find their focus nodes, and notify the listeners of the results. |
| 24 | + */ |
| 25 | +public class ShapeFocusNodesResolver { |
23 | 26 |
|
24 | 27 | protected Model shapeModel;
|
25 | 28 | protected Model data;
|
26 | 29 |
|
| 30 | + protected List<FocusNodeListener> listeners = new ArrayList<FocusNodeListener>(); |
| 31 | + |
27 | 32 |
|
28 |
| - public ShapeTargetResolver(Model shapeModel, Model data) { |
| 33 | + public ShapeFocusNodesResolver(Model shapeModel, Model data) { |
29 | 34 | super();
|
30 | 35 | this.shapeModel = shapeModel;
|
31 | 36 | this.data = data;
|
32 | 37 | }
|
33 | 38 |
|
34 |
| - public void resolveFocusNodes(FocusNodeProcessor p) { |
| 39 | + public void resolveFocusNodes() { |
35 | 40 |
|
36 | 41 | // for each subject of a target predicate...
|
37 | 42 | List<Resource> shapes = shapeModel.listResourcesWithProperty(SH.targetNode)
|
38 | 43 | .andThen(shapeModel.listResourcesWithProperty(SH.targetClass))
|
39 | 44 | .andThen(shapeModel.listResourcesWithProperty(SH.targetSubjectsOf))
|
40 | 45 | .andThen(shapeModel.listResourcesWithProperty(SH.targetObjectsOf))
|
41 |
| - .andThen(shapeModel.listResourcesWithProperty(RDF.type, RDFS.Class)) |
42 |
| - .andThen(shapeModel.listResourcesWithProperty(RDF.type, OWL.Class)) |
| 46 | + .andThen(shapeModel.listResourcesWithProperty(RDF.type, RDFS.Class).filterKeep(r -> r.hasProperty(RDF.type, SH.NodeShape))) |
| 47 | + .andThen(shapeModel.listResourcesWithProperty(RDF.type, OWL.Class).filterKeep(r -> r.hasProperty(RDF.type, SH.NodeShape))) |
43 | 48 | // generic SPARQL-based targets
|
44 | 49 | .andThen(shapeModel.listResourcesWithProperty(SH.target)).toList();
|
45 | 50 |
|
46 |
| - for (Resource r : shapes) { |
47 |
| - List<RDFNode> focusNodes = resolveFocusNodes(r, data); |
48 |
| - // TODO |
| 51 | + for (Resource shape : shapes) { |
| 52 | + resolveFocusNodes(shape, data); |
| 53 | + } |
| 54 | + |
| 55 | + // notify of end |
| 56 | + for(FocusNodeListener listener : listeners) { |
| 57 | + listener.notifyEnd(); |
49 | 58 | }
|
50 | 59 | }
|
51 | 60 |
|
52 |
| - private List<RDFNode> resolveFocusNodes(Resource shape, Model data) { |
53 |
| - List<RDFNode> focusNodes = new ArrayList<RDFNode>(); |
54 |
| - |
| 61 | + public void setListeners(List<FocusNodeListener> listeners) { |
| 62 | + this.listeners = listeners; |
| 63 | + } |
| 64 | + |
| 65 | + public List<FocusNodeListener> getListeners() { |
| 66 | + return this.listeners; |
| 67 | + } |
| 68 | + |
| 69 | + private void resolveFocusNodes(Resource shape, Model data) { |
| 70 | + |
55 | 71 | // * sh:targetNode
|
56 | 72 | StmtIterator it = shape.listProperties(SH.targetNode);
|
57 | 73 | while(it.hasNext()) {
|
58 |
| - focusNodes.addAll(resolveTargetNode(it.next().getObject().asResource(), data)); |
| 74 | + notifyListeners( |
| 75 | + shape, |
| 76 | + data, |
| 77 | + resolveTargetNode(it.next().getObject().asResource(), data) |
| 78 | + ); |
59 | 79 | }
|
60 | 80 |
|
61 | 81 | // * sh:targetClass
|
62 | 82 | it = shape.listProperties(SH.targetClass);
|
63 | 83 | while(it.hasNext()) {
|
64 |
| - focusNodes.addAll(resolveTargetClass(it.next().getObject().asResource(), data)); |
| 84 | + notifyListeners( |
| 85 | + shape, |
| 86 | + data, |
| 87 | + resolveTargetClass(it.next().getObject().asResource(), data) |
| 88 | + ); |
65 | 89 | }
|
66 | 90 |
|
67 | 91 | // * implicit targetClass if the shape is also a class
|
68 | 92 | if(shape.hasProperty(RDF.type, RDFS.Class)) {
|
69 |
| - focusNodes.addAll(resolveTargetClass(shape, data)); |
| 93 | + notifyListeners( |
| 94 | + shape, |
| 95 | + data, |
| 96 | + resolveTargetClass(shape, data) |
| 97 | + ); |
70 | 98 | }
|
71 | 99 |
|
72 | 100 | // * sh:targetSubjectsOf
|
73 | 101 | it = shape.listProperties(SH.targetSubjectsOf);
|
74 | 102 | while(it.hasNext()) {
|
75 |
| - focusNodes.addAll(resolveTargetSubjectsOf(it.next().getObject().asResource(), data)); |
| 103 | + notifyListeners( |
| 104 | + shape, |
| 105 | + data, |
| 106 | + resolveTargetSubjectsOf(it.next().getObject().asResource(), data) |
| 107 | + ); |
76 | 108 | }
|
77 | 109 |
|
78 | 110 | // * sh:targetObjectsOf
|
79 | 111 | it = shape.listProperties(SH.targetObjectsOf);
|
80 | 112 | while(it.hasNext()) {
|
81 |
| - focusNodes.addAll(resolveTargetObjectsOf(it.next().getObject().asResource(), data)); |
| 113 | + notifyListeners( |
| 114 | + shape, |
| 115 | + data, |
| 116 | + resolveTargetObjectsOf(it.next().getObject().asResource(), data) |
| 117 | + ); |
82 | 118 | }
|
83 | 119 |
|
84 | 120 | // * sh:target
|
85 | 121 | it = shape.listProperties(SH.target);
|
86 | 122 | while(it.hasNext()) {
|
87 | 123 | Resource shTargetValue = it.next().getObject().asResource();
|
88 | 124 | if(shTargetValue.hasProperty(SH.select)) {
|
89 |
| - focusNodes.addAll(resolveTargetSparql(shTargetValue.getProperty(SH.select).getObject().asLiteral().getLexicalForm(), data)); |
| 125 | + notifyListeners( |
| 126 | + shape, |
| 127 | + data, |
| 128 | + resolveTargetSparql(shTargetValue.getProperty(SH.select).getObject().asLiteral().getLexicalForm(), data) |
| 129 | + ); |
90 | 130 | }
|
91 | 131 | }
|
92 |
| - |
93 |
| - return focusNodes; |
| 132 | + |
| 133 | + // notify of end shape |
| 134 | + for(FocusNodeListener listener : listeners) { |
| 135 | + listener.notifyEndShape(shape, data); |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + private void notifyListeners(Resource shape, Model data, List<RDFNode> focusNodes) { |
| 140 | + for(FocusNodeListener listener : listeners) { |
| 141 | + listener.notifyFocusNodes(shape, data, focusNodes); |
| 142 | + } |
94 | 143 | }
|
95 | 144 |
|
96 | 145 | private List<RDFNode> resolveTargetNode(Resource targetNode, Model data) {
|
@@ -118,10 +167,11 @@ private List<RDFNode> resolveTargetClass(Resource targetClass, Model data) {
|
118 | 167 | }
|
119 | 168 | }
|
120 | 169 |
|
121 |
| - private List<Resource> resolveTargetSubjectsOf(Resource targetSubjectsOf, Model data) { |
122 |
| - return data.listSubjectsWithProperty(data.createProperty(targetSubjectsOf.getURI())).toList(); |
| 170 | + private List<RDFNode> resolveTargetSubjectsOf(Resource targetSubjectsOf, Model data) { |
| 171 | + List<Resource> resources = data.listSubjectsWithProperty(data.createProperty(targetSubjectsOf.getURI())).toList(); |
| 172 | + // cast to a List<RDFNode> to match the return type |
| 173 | + return new ArrayList<RDFNode>(resources); |
123 | 174 | }
|
124 |
| - |
125 | 175 | private List<RDFNode> resolveTargetObjectsOf(Resource targetObjectsOf, Model data) {
|
126 | 176 | return data.listObjectsOfProperty(data.createProperty(targetObjectsOf.getURI())).toList();
|
127 | 177 | }
|
|
0 commit comments