|
8 | 8 | import com.hp.hpl.jena.util.iterator.Filter;
|
9 | 9 | import com.hp.hpl.jena.util.iterator.UniqueExtendedIterator;
|
10 | 10 | import org.apache.commons.lang3.time.StopWatch;
|
| 11 | +import org.slf4j.Logger; |
| 12 | +import org.slf4j.LoggerFactory; |
11 | 13 |
|
12 | 14 | import javax.annotation.Nullable;
|
13 | 15 | import java.util.*;
|
|
18 | 20 |
|
19 | 21 | class JenaUtils {
|
20 | 22 |
|
| 23 | + protected static Logger log = LoggerFactory.getLogger( JenaUtils.class ); |
| 24 | + |
21 | 25 | public static Collection<OntClass> getParents( OntModel model, Collection<OntClass> ontClasses, boolean direct, @Nullable Set<Restriction> additionalRestrictions ) {
|
| 26 | + Collection<OntClass> parents = getParentsInternal( model, ontClasses, direct, additionalRestrictions ); |
| 27 | + if ( shouldRevisit( parents, direct, model, additionalRestrictions ) ) { |
| 28 | + // if there are some missing direct parents, revisit the hierarchy |
| 29 | + Set<OntClass> parentsToRevisit = new HashSet<>( parents ); |
| 30 | + while ( !parentsToRevisit.isEmpty() ) { |
| 31 | + log.debug( "Revisiting the direct parents of {} terms...", parentsToRevisit.size() ); |
| 32 | + parentsToRevisit = new HashSet<>( getParentsInternal( model, parentsToRevisit, true, additionalRestrictions ) ); |
| 33 | + parentsToRevisit.removeAll( parents ); |
| 34 | + log.debug( "Found {} missed parents.", parentsToRevisit.size() ); |
| 35 | + parents.addAll( parentsToRevisit ); |
| 36 | + } |
| 37 | + } |
| 38 | + return parents; |
| 39 | + } |
| 40 | + |
| 41 | + private static Collection<OntClass> getParentsInternal( OntModel model, Collection<OntClass> ontClasses, boolean direct, @Nullable Set<Restriction> additionalRestrictions ) { |
22 | 42 | ontClasses = ontClasses.stream()
|
23 | 43 | .map( t -> t.inModel( model ) )
|
24 | 44 | .filter( t -> t.canAs( OntClass.class ) )
|
@@ -65,6 +85,22 @@ public static Collection<OntClass> getParents( OntModel model, Collection<OntCla
|
65 | 85 | }
|
66 | 86 |
|
67 | 87 | public static Collection<OntClass> getChildren( OntModel model, Collection<OntClass> terms, boolean direct, @Nullable Set<Restriction> additionalRestrictions ) {
|
| 88 | + Collection<OntClass> children = getChildrenInternal( model, terms, direct, additionalRestrictions ); |
| 89 | + if ( shouldRevisit( children, direct, model, additionalRestrictions ) ) { |
| 90 | + // if there are some missing direct children, revisit the hierarchy |
| 91 | + Set<OntClass> childrenToRevisit = new HashSet<>( children ); |
| 92 | + while ( !childrenToRevisit.isEmpty() ) { |
| 93 | + log.debug( "Revisiting the direct parents of {} terms...", childrenToRevisit.size() ); |
| 94 | + childrenToRevisit = new HashSet<>( JenaUtils.getChildrenInternal( model, childrenToRevisit, true, additionalRestrictions ) ); |
| 95 | + childrenToRevisit.removeAll( children ); |
| 96 | + log.debug( "Found {} missed children.", childrenToRevisit.size() ); |
| 97 | + children.addAll( childrenToRevisit ); |
| 98 | + } |
| 99 | + } |
| 100 | + return children; |
| 101 | + } |
| 102 | + |
| 103 | + public static Collection<OntClass> getChildrenInternal( OntModel model, Collection<OntClass> terms, boolean direct, @Nullable Set<Restriction> additionalRestrictions ) { |
68 | 104 | terms = terms.stream()
|
69 | 105 | .map( t -> t.inModel( model ) )
|
70 | 106 | .filter( t -> t.canAs( OntClass.class ) )
|
@@ -103,6 +139,42 @@ public static Collection<OntClass> getChildren( OntModel model, Collection<OntCl
|
103 | 139 | return result;
|
104 | 140 | }
|
105 | 141 |
|
| 142 | + /** |
| 143 | + * Check if a set of terms should be revisited to find missing parents or children. |
| 144 | + * <p> |
| 145 | + * To be considered, the model must have a reasoner that lacks one of {@code rdfs:subClassOf}, {@code owl:subValuesFrom} |
| 146 | + * or {@code owl:allValuesFrom} inference capabilities. If a model has no reasoner, revisiting is not desirable and |
| 147 | + * thus this will return false. |
| 148 | + * <p> |
| 149 | + * If direct is false or terms is empty, it's not worth revisiting. |
| 150 | + */ |
| 151 | + private static boolean shouldRevisit( Collection<OntClass> terms, boolean direct, OntModel model, @Nullable Set<Restriction> additionalRestrictions ) { |
| 152 | + return !direct |
| 153 | + && !terms.isEmpty() |
| 154 | + && additionalRestrictions != null |
| 155 | + && model.getReasoner() != null |
| 156 | + && ( !supportsSubClassInference( model ) || !supportsAdditionalRestrictionsInference( model ) ); |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * Check if an ontology model supports inference of {@code rdfs:subClassOf}. |
| 161 | + */ |
| 162 | + public static boolean supportsSubClassInference( OntModel model ) { |
| 163 | + return model.getReasoner() != null |
| 164 | + && model.getReasoner().supportsProperty( model.getProfile().SUB_CLASS_OF() ); |
| 165 | + } |
| 166 | + |
| 167 | + /** |
| 168 | + * Checks if an ontology model supports inference of with additional restrictions. |
| 169 | + * <p> |
| 170 | + * This covers {@code owl:subValuesFrom} and {@code owl:allValuesFrom} restrictions. |
| 171 | + */ |
| 172 | + public static boolean supportsAdditionalRestrictionsInference( OntModel model ) { |
| 173 | + return model.getReasoner() != null |
| 174 | + && model.getReasoner().supportsProperty( model.getProfile().SOME_VALUES_FROM() ) |
| 175 | + && model.getReasoner().supportsProperty( model.getProfile().ALL_VALUES_FROM() ); |
| 176 | + } |
| 177 | + |
106 | 178 | public static Resource getRestrictionValue( Restriction r ) {
|
107 | 179 | if ( r.isSomeValuesFromRestriction() ) {
|
108 | 180 | return r.asSomeValuesFromRestriction().getSomeValuesFrom();
|
|
0 commit comments