Skip to content

Commit d43dcb2

Browse files
committed
ont-api: add model-impl for SWRLRule axiom (issue #2), minor changes in OWLObjectImpl, ONTStatementImpl, add and fix tests
1 parent 272ec1c commit d43dcb2

File tree

10 files changed

+392
-59
lines changed

10 files changed

+392
-59
lines changed

src/main/java/com/github/owlcs/ontapi/internal/AxiomTranslator.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,8 @@ protected abstract ONTObject<Axiom> toAxiom(OntStatement statement,
278278
* @throws JenaException if no possible to get axiom from the statement
279279
* @since 2.0.0
280280
*/
281-
protected ONTObject<Axiom> toAxiom(OntStatement statement,
282-
Supplier<OntGraphModel> model,
283-
InternalObjectFactory factory,
284-
InternalConfig config) throws JenaException {
285-
return toAxiom(statement, factory, config);
286-
}
281+
protected abstract ONTObject<Axiom> toAxiom(OntStatement statement,
282+
Supplier<OntGraphModel> model,
283+
InternalObjectFactory factory,
284+
InternalConfig config) throws JenaException;
287285
}

src/main/java/com/github/owlcs/ontapi/internal/axioms/SWRLRuleTranslator.java

+219-8
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@
1515
package com.github.owlcs.ontapi.internal.axioms;
1616

1717
import com.github.owlcs.ontapi.internal.*;
18-
import com.github.owlcs.ontapi.jena.model.OntGraphModel;
19-
import com.github.owlcs.ontapi.jena.model.OntObject;
20-
import com.github.owlcs.ontapi.jena.model.OntSWRL;
21-
import com.github.owlcs.ontapi.jena.model.OntStatement;
18+
import com.github.owlcs.ontapi.internal.objects.*;
19+
import com.github.owlcs.ontapi.jena.model.*;
20+
import com.github.owlcs.ontapi.jena.utils.Iter;
2221
import com.github.owlcs.ontapi.jena.utils.OntModels;
22+
import com.github.owlcs.ontapi.owlapi.axioms.SWRLRuleImpl;
23+
import org.apache.jena.graph.FrontsTriple;
24+
import org.apache.jena.graph.Triple;
2325
import org.apache.jena.util.iterator.ExtendedIterator;
24-
import org.semanticweb.owlapi.model.OWLAnnotation;
25-
import org.semanticweb.owlapi.model.SWRLAtom;
26-
import org.semanticweb.owlapi.model.SWRLRule;
26+
import org.semanticweb.owlapi.model.*;
2727

28-
import java.util.Collection;
28+
import java.util.*;
29+
import java.util.function.Supplier;
2930
import java.util.stream.Collectors;
3031
import java.util.stream.Stream;
3132

@@ -56,6 +57,14 @@ public boolean testStatement(OntStatement statement, InternalConfig config) {
5657
return statement.getSubject().canAs(OntSWRL.Imp.class);
5758
}
5859

60+
@Override
61+
public ONTObject<SWRLRule> toAxiom(OntStatement statement,
62+
Supplier<OntGraphModel> model,
63+
InternalObjectFactory factory,
64+
InternalConfig config) {
65+
return AxiomImpl.create(statement, model, factory, config);
66+
}
67+
5968
@Override
6069
public ONTObject<SWRLRule> toAxiom(OntStatement statement, InternalObjectFactory factory, InternalConfig config) {
6170
OntSWRL.Imp imp = statement.getSubject(OntSWRL.Imp.class);
@@ -73,4 +82,206 @@ public ONTObject<SWRLRule> toAxiom(OntStatement statement, InternalObjectFactory
7382
return ONTWrapperImpl.create(res, imp).append(annotations).append(body).append(head);
7483
}
7584

85+
/**
86+
* @see SWRLRuleImpl
87+
*/
88+
public static class AxiomImpl extends ONTAxiomImpl<SWRLRule> implements WithContent<AxiomImpl>, SWRLRule {
89+
protected final InternalCache.Loading<AxiomImpl, Object[]> content;
90+
91+
public AxiomImpl(Triple t, Supplier<OntGraphModel> m) {
92+
super(t, m);
93+
this.content = createContentCache();
94+
}
95+
96+
/**
97+
* Creates an {@link ONTObject} container that is also {@link SWRLRule}.
98+
*
99+
* @param statement {@link OntStatement}, not {@code null}
100+
* @param model {@link OntGraphModel} provider, not {@code null}
101+
* @param factory {@link InternalObjectFactory}, not {@code null}
102+
* @param config {@link InternalConfig}, not {@code null}
103+
* @return {@link AxiomImpl}
104+
*/
105+
@SuppressWarnings("unused")
106+
public static AxiomImpl create(OntStatement statement,
107+
Supplier<OntGraphModel> model,
108+
InternalObjectFactory factory,
109+
InternalConfig config) {
110+
return new AxiomImpl(statement.asTriple(), model);
111+
}
112+
113+
private static Collection<ONTObject<? extends SWRLAtom>> collectAtoms(OntList<OntSWRL.Atom> list,
114+
InternalObjectFactory factory) {
115+
return Iter.addAll(OntModels.listMembers(list).mapWith(factory::getSWRLAtom), new ArrayList<>());
116+
}
117+
118+
@SuppressWarnings("unchecked")
119+
private static <X extends OWLObject> Stream<X> content(Class<X> type, Object[] content, int index) {
120+
Object[] arr = (Object[]) content[index];
121+
return Arrays.stream(arr).map(x -> type.isInstance(x) ? (X) x : ((ONTObject<? extends X>) x).getOWLObject());
122+
}
123+
124+
@SuppressWarnings({"unchecked", "SameParameterValue"})
125+
private static <X extends OWLObject> List<X> getContentAsList(Class<X> type, Object[] content, int index) {
126+
Object[] arr = (Object[]) content[index];
127+
if (arr.length == 0) {
128+
return Collections.emptyList();
129+
}
130+
if (type.isInstance(arr[0])) {
131+
List res = Arrays.asList(arr);
132+
return Collections.unmodifiableList(res);
133+
}
134+
return Arrays.stream(arr).map(x -> ((ONTObject<X>) x).getOWLObject()).collect(Collectors.toList());
135+
}
136+
137+
@Override
138+
public InternalCache.Loading<AxiomImpl, Object[]> getContentCache() {
139+
return content;
140+
}
141+
142+
public OntSWRL.Imp asResource() {
143+
return getPersonalityModel().getNodeAs(getSubjectNode(), OntSWRL.Imp.class);
144+
}
145+
146+
@Override
147+
public OntStatement asStatement() {
148+
return asResource().getRoot();
149+
}
150+
151+
@Override
152+
public Object[] collectContent() {
153+
OntSWRL.Imp imp = asResource();
154+
InternalObjectFactory factory = getObjectFactory();
155+
Collection<ONTObject<OWLAnnotation>> annotations = collectAnnotations(imp.getRoot(), factory, getConfig());
156+
Object[] res;
157+
if (annotations.isEmpty()) {
158+
res = new Object[2];
159+
} else {
160+
res = new Object[3];
161+
res[2] = annotations.toArray();
162+
}
163+
// may contain duplicates:
164+
res[0] = collectAtoms(imp.getHeadList(), factory).toArray();
165+
res[1] = collectAtoms(imp.getBodyList(), factory).toArray();
166+
return res;
167+
}
168+
169+
@Override
170+
public Stream<Triple> triples() {
171+
return Stream.concat(asResource().spec().map(FrontsTriple::asTriple),
172+
objects().flatMap(ONTObject::triples));
173+
}
174+
175+
@SuppressWarnings("unchecked")
176+
@Override
177+
public Stream<ONTObject<? extends OWLObject>> objects() {
178+
Stream res = Arrays.stream(getContent()).flatMap(x -> Arrays.stream((Object[]) x));
179+
return (Stream<ONTObject<? extends OWLObject>>) res;
180+
}
181+
182+
@Override
183+
public Stream<SWRLAtom> body() {
184+
return content(SWRLAtom.class, getContent(), 1).distinct();
185+
}
186+
187+
@Override
188+
public Stream<SWRLAtom> head() {
189+
return content(SWRLAtom.class, getContent(), 0).distinct();
190+
}
191+
192+
@Override
193+
public Stream<SWRLVariable> variables() {
194+
return SWRLRuleImpl.variables(this);
195+
}
196+
197+
@Override
198+
public boolean containsAnonymousClassExpressions() {
199+
return classAtomPredicates().anyMatch(OWLClassExpression::isAnonymous);
200+
}
201+
202+
@Override
203+
public Stream<OWLClassExpression> classAtomPredicates() {
204+
return SWRLRuleImpl.classAtomPredicates(this);
205+
}
206+
207+
@Override
208+
public boolean isAnnotated() {
209+
return getContent().length == 3;
210+
}
211+
212+
@Override
213+
public Stream<OWLAnnotation> annotations() {
214+
Object[] content = getContent();
215+
if (content.length == 3) {
216+
return content(OWLAnnotation.class, content, 2);
217+
}
218+
return Stream.empty();
219+
}
220+
221+
@Override
222+
public List<OWLAnnotation> annotationsAsList() {
223+
Object[] content = getContent();
224+
if (content.length != 3) {
225+
return Collections.emptyList();
226+
}
227+
return getContentAsList(OWLAnnotation.class, content, 2);
228+
}
229+
230+
@Override
231+
public boolean canContainAnnotationProperties() {
232+
return isAnnotated();
233+
}
234+
235+
@FactoryAccessor
236+
@Override
237+
public SWRLRule getSimplified() {
238+
return eraseModel().getSimplified();
239+
}
240+
241+
@FactoryAccessor
242+
@Override
243+
protected SWRLRule createAnnotatedAxiom(Collection<OWLAnnotation> annotations) {
244+
return getDataFactory().getSWRLRule(body().map(ONTObjectImpl::eraseModel).collect(Collectors.toList()),
245+
head().map(ONTObjectImpl::eraseModel).collect(Collectors.toList()), annotations);
246+
}
247+
248+
@Override
249+
protected boolean sameContent(ONTStatementImpl other) {
250+
return other instanceof AxiomImpl && Arrays.deepEquals(getContent(), ((AxiomImpl) other).getContent());
251+
}
252+
253+
@Override
254+
protected boolean sameComponents(HasComponents other) {
255+
SWRLRule rule = (SWRLRule) other;
256+
return sameAnnotations(rule) && equalStreams(body(), rule.body()) && equalStreams(head(), rule.head());
257+
}
258+
259+
private boolean sameAnnotations(OWLAxiom other) {
260+
if (isAnnotated()) {
261+
return other.isAnnotated() && annotationsAsList().equals(other.annotationsAsList());
262+
}
263+
return !other.isAnnotated();
264+
}
265+
266+
@Override
267+
public ONTObject<SWRLRule> merge(ONTObject<SWRLRule> other) {
268+
if (this == other) {
269+
return this;
270+
}
271+
if (other instanceof AxiomImpl && sameTriple((AxiomImpl) other)) {
272+
return this;
273+
}
274+
AxiomImpl res = new AxiomImpl(asTriple(), model) {
275+
@Override
276+
public Stream<Triple> triples() {
277+
return Stream.concat(AxiomImpl.this.triples(), other.triples());
278+
}
279+
};
280+
if (hasContent()) {
281+
res.putContent(getContent());
282+
}
283+
res.hashCode = hashCode;
284+
return res;
285+
}
286+
}
76287
}

src/main/java/com/github/owlcs/ontapi/internal/objects/ONTStatementImpl.java

+16-6
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@
1414

1515
package com.github.owlcs.ontapi.internal.objects;
1616

17+
import com.github.owlcs.ontapi.OntApiException;
18+
import com.github.owlcs.ontapi.jena.model.OntGraphModel;
19+
import com.github.owlcs.ontapi.jena.model.OntStatement;
20+
import com.github.owlcs.ontapi.jena.utils.Iter;
1721
import org.apache.jena.graph.*;
1822
import org.apache.jena.graph.impl.LiteralLabel;
1923
import org.apache.jena.rdf.model.RDFNode;
24+
import org.semanticweb.owlapi.model.HasComponents;
2025
import org.semanticweb.owlapi.model.OWLAnnotation;
2126
import org.semanticweb.owlapi.model.OWLObject;
22-
import com.github.owlcs.ontapi.OntApiException;
23-
import com.github.owlcs.ontapi.jena.model.OntGraphModel;
24-
import com.github.owlcs.ontapi.jena.model.OntStatement;
25-
import com.github.owlcs.ontapi.jena.utils.Iter;
2627

2728
import javax.annotation.Nullable;
2829
import java.util.Collection;
@@ -245,6 +246,16 @@ protected final boolean sameObject(ONTStatementImpl other) {
245246
*/
246247
protected abstract boolean sameContent(ONTStatementImpl other);
247248

249+
/**
250+
* Answers {@code true} if this object and the specified have the same components.
251+
*
252+
* @param other {@link HasComponents}, not {@code null}
253+
* @return boolean
254+
*/
255+
protected boolean sameComponents(HasComponents other) {
256+
return equalStreams(components(), other.components());
257+
}
258+
248259
/**
249260
* Answers {@code true} if this object and the given are equal as {@link OWLObject} (i.e. in OWL-API terms).
250261
*
@@ -290,7 +301,6 @@ public final boolean equals(@Nullable Object obj) {
290301
if (hashCode() != other.hashCode()) {
291302
return false;
292303
}
293-
return equalIterators(components().iterator(), other.components().iterator());
304+
return sameComponents(other);
294305
}
295-
296306
}

src/main/java/com/github/owlcs/ontapi/owlapi/OWLObjectImpl.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
*/
1414
package com.github.owlcs.ontapi.owlapi;
1515

16+
import com.github.owlcs.ontapi.jena.utils.Iter;
1617
import org.semanticweb.owlapi.model.*;
1718
import org.semanticweb.owlapi.util.AbstractCollectorEx;
1819
import org.semanticweb.owlapi.util.OWLClassExpressionCollector;
1920
import org.semanticweb.owlapi.util.OWLEntityCollector;
2021
import org.semanticweb.owlapi.util.SimpleRenderer;
21-
import com.github.owlcs.ontapi.jena.utils.Iter;
2222

2323
import javax.annotation.Nullable;
2424
import javax.annotation.ParametersAreNonnullByDefault;
@@ -159,7 +159,8 @@ protected static List<OWLAnnotation> prepareAnnotations(Collection<OWLAnnotation
159159

160160
/**
161161
* Checks the iterator contents for equality (sensitive to order).
162-
* It was moved from the {@link org.semanticweb.owlapi.util.OWLAPIStreamUtils} to control behaviour.
162+
* This method has been moved here from the {@link org.semanticweb.owlapi.util.OWLAPIStreamUtils}
163+
* to better control behaviour.
163164
*
164165
* @param left {@code Iterator} to compare, not {@code null}
165166
* @param right {@code Iterator} to compare, not {@code null}
@@ -183,6 +184,18 @@ protected static boolean equalIterators(Iterator left, Iterator right) {
183184
return left.hasNext() == right.hasNext();
184185
}
185186

187+
/**
188+
* Checks streams for equality (sensitive to order)
189+
*
190+
* @param left {@code Stream} to compare, not {@code null}
191+
* @param right {@code Stream} to compare, not {@code null}
192+
* @return {@code true} if the streams have the same content, {@code false} otherwise
193+
* @see org.semanticweb.owlapi.util.OWLAPIStreamUtils#equalStreams(Stream, Stream)
194+
*/
195+
protected static boolean equalStreams(Stream left, Stream right) {
196+
return equalIterators(left.iterator(), right.iterator());
197+
}
198+
186199
/**
187200
* Compares iterators element by element (sensitive to order).
188201
* It was moved from the {@link org.semanticweb.owlapi.util.OWLAPIStreamUtils} to control behaviour.

0 commit comments

Comments
 (0)