33
33
import org .apache .jena .rdf .model .RDFNode ;
34
34
import org .apache .jena .rdf .model .Resource ;
35
35
import org .apache .jena .rdf .model .Statement ;
36
+ import org .apache .jena .rdf .model .StmtIterator ;
36
37
import org .apache .jena .sparql .core .Var ;
37
38
import org .apache .jena .sparql .engine .binding .Binding ;
38
39
import org .apache .jena .vocabulary .RDF ;
@@ -84,16 +85,27 @@ public List<Violation> validateModel( final VersionedModel versionedModel ) {
84
85
initializeQuery ( metaModelVersion .get () );
85
86
86
87
// we only want to investigate properties that are directly reachable from an Aspect
87
- final Statement aspect = model .listStatements ( null , RDF .type , bamm .Aspect () ).nextStatement ();
88
- final Statement properties = aspect .getSubject ().getProperty ( bamm .properties () );
89
- if ( properties != null ) {
90
- final Iterator <RDFNode > aspectProperties = properties .getList ().iterator ();
91
- while ( aspectProperties .hasNext () ) {
92
- final RDFNode propRef = aspectProperties .next ();
93
- final Statement property = model .listStatements ( propRef .asResource (), RDF .type , bamm .Property () ).nextStatement ();
94
- final String propertyName = getUniqueName ( property .getSubject () );
95
- if ( !discovered .contains ( propertyName ) && !finished .contains ( propertyName ) ) {
96
- depthFirstTraversal ( property .getSubject (), this ::reportCycle );
88
+ final StmtIterator aspects = model .listStatements ( null , RDF .type , bamm .Aspect () );
89
+ if ( aspects .hasNext () ) {
90
+ final Statement aspect = aspects .nextStatement ();
91
+ final Statement properties = aspect .getSubject ().getProperty ( bamm .properties () );
92
+ if ( properties != null ) {
93
+ final Iterator <RDFNode > aspectProperties = properties .getList ().iterator ();
94
+ while ( aspectProperties .hasNext () ) {
95
+ final RDFNode propRef = aspectProperties .next ();
96
+ final Resource property ;
97
+ if ( propRef .isAnon () ) {
98
+ if ( isOptionalProperty ( propRef .asResource () ) ) {
99
+ continue ;
100
+ }
101
+ property = resolvePropertyReference ( propRef .asResource () );
102
+ } else {
103
+ property = propRef .asResource ();
104
+ }
105
+ final String propertyName = getUniqueName ( property );
106
+ if ( !discovered .contains ( propertyName ) && !finished .contains ( propertyName ) ) {
107
+ depthFirstTraversal ( property , this ::reportCycle );
108
+ }
97
109
}
98
110
}
99
111
}
@@ -134,19 +146,14 @@ private boolean reachedViaEither( final List<NextHopProperty> nextHopProperties
134
146
}
135
147
136
148
private void investigateProperty ( Resource propertyNode , final BiConsumer <String , Set <String >> cycleHandler ) {
137
- // property usage of the type "[ bamm:property :propName ; bamm:optional value ; ]"
138
149
if ( propertyNode .isAnon () ) {
139
- final Statement optional = propertyNode . getProperty ( bamm . optional () );
140
- if ( ( optional != null ) && optional . getBoolean ( ) ) {
150
+ // [ bamm:property :propName ; bamm: optional value ; ]
151
+ if ( isOptionalProperty ( propertyNode ) ) {
141
152
// presence of bamm:optional = true; no need to continue on this path, the potential cycle would be broken by the optional property anyway
142
153
return ;
143
154
}
144
155
145
- // resolve property reference
146
- final Statement prop = propertyNode .getProperty ( bamm .property () );
147
- if ( prop != null ) {
148
- propertyNode = prop .getObject ().asResource ();
149
- }
156
+ propertyNode = resolvePropertyReference ( propertyNode );
150
157
}
151
158
152
159
final String propertyName = getUniqueName ( propertyNode );
@@ -159,6 +166,19 @@ private void investigateProperty( Resource propertyNode, final BiConsumer<String
159
166
}
160
167
}
161
168
169
+ private Resource resolvePropertyReference ( final Resource propertyNode ) {
170
+ final Statement prop = propertyNode .getProperty ( bamm .property () );
171
+ if ( prop != null ) {
172
+ return prop .getObject ().asResource ();
173
+ }
174
+ return propertyNode ;
175
+ }
176
+
177
+ private boolean isOptionalProperty ( final Resource propertyNode ) {
178
+ final Statement optional = propertyNode .getProperty ( bamm .optional () );
179
+ return (optional != null ) && optional .getBoolean ();
180
+ }
181
+
162
182
private String getUniqueName ( final Resource property ) {
163
183
// Ugly special case: when extending Entities, the property name will always be the same ([ bamm:extends bamm-e:value ; bamm:characteristic :someChara ]),
164
184
// so we need a unique name in case more than one extending Entity exists in the model
@@ -175,6 +195,7 @@ private String getUniqueName( final Resource property ) {
175
195
176
196
private String findExtendingEntityName ( final Resource extendsProperty ) {
177
197
return model .listSubjectsWithProperty ( bamm ._extends () )
198
+ .filterKeep ( entity -> entity .getProperty ( bamm .properties () ) != null )
178
199
.filterKeep ( entity -> entity .getProperty ( bamm .properties () ).getList ().contains ( extendsProperty ) )
179
200
.mapWith ( resource -> model .shortForm ( resource .getURI () ) )
180
201
.nextOptional ().orElse ( extendsProperty .toString () );
0 commit comments