io.konig.core.showl.ShowlPropertyShape Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of konig-core Show documentation
Show all versions of konig-core Show documentation
A library for core classes (Graph, Vertex, Edge, etc.)
package io.konig.core.showl;
/*
* #%L
* Konig Core
* %%
* Copyright (C) 2015 - 2018 Gregory McFall
* %%
* Licensed 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
*
* http://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.
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.konig.core.OwlReasoner;
import io.konig.core.impl.RdfUtil;
import io.konig.core.vocab.Konig;
import io.konig.formula.Direction;
import io.konig.formula.DirectionStep;
import io.konig.formula.PathExpression;
import io.konig.formula.PathStep;
import io.konig.formula.PrimaryExpression;
import io.konig.formula.QuantifiedExpression;
import io.konig.shacl.NodeKind;
import io.konig.shacl.PropertyConstraint;
import io.konig.shacl.Shape;
public abstract class ShowlPropertyShape implements Traversable {
private static final Logger logger = LoggerFactory.getLogger(ShowlPropertyShape.class);
private ShowlNodeShape declaringShape;
protected ShowlProperty property;
private PropertyConstraint propertyConstraint;
private ShowlNodeShape valueShape;
private Map mappings;
private Map joinConditions;
private ShowlMapping selectedMapping;
private Set hasValueDeprecated;
private ShowlExpression selectedExpression;
private Set peerGroup = new HashSet<>();
private Set hasValue;
private ShowlExpression formula;
private Set usedIn;
private List expressionList = new ArrayList<>();
private ShowlPropertyShapeGroup targetProperty;
public ShowlPropertyShape(ShowlNodeShape declaringShape, ShowlProperty property, PropertyConstraint propertyConstraint) {
this.declaringShape = declaringShape;
this.property = property;
this.propertyConstraint = propertyConstraint;
}
public NodeKind getNodeKind() {
return propertyConstraint == null ? null : propertyConstraint.getNodeKind();
}
public void addMapping(ShowlMapping mapping) {
if (mappings==null) {
mappings = new HashMap<>();
}
mappings.put(mapping.getJoinCondition(), mapping);
}
public boolean isRequired() {
ShowlPropertyShape delegate = maybeDirect();
PropertyConstraint constraint = delegate.getPropertyConstraint();
if (constraint != null) {
Integer minCount = constraint.getMinCount();
return minCount!=null && minCount>0;
} else if (Konig.id.equals(getPredicate())) {
// This is a bit of a hack. We assume that whenever the konig:id property
// is declared that it is required.
// We really ought to generate a PropertyConstraint when the konig:id pseudo-property is generated
// to specify whether the field is required.
return true;
}
return false;
}
public Collection getMappings() {
return mappings==null ? Collections.emptySet() : mappings.values();
}
public Collection listJoinConditions() {
Set set = new HashSet<>();
for (ShowlMapping m : getMappings()) {
set.add(m.getJoinCondition());
}
return set;
}
/**
* Get the mapping for this property within the given join condition.
* @param joinCondition The join condition for which the mapping is requested.
* @return The mapping for this property within the join condition, or null if no mapping exists.
*/
public ShowlMapping getMapping(ShowlJoinCondition joinCondition) {
return mappings==null ? null : mappings.get(joinCondition);
}
/**
* Returns true if this PropertyShape describes a direct property (i.e. not derived).
*/
public boolean isDirect() {
return true;
}
public boolean isLeaf() {
return valueShape==null;
}
public boolean isEnumIndividual(OwlReasoner reasoner) {
Resource owlClassId = null;
if (Konig.id.equals(getPredicate())) {
owlClassId = getDeclaringShape().getOwlClass().getId();
} else {
owlClassId = getOwlClassId();
}
return owlClassId==null ? false : reasoner.isEnumerationClass(owlClassId);
}
public URI getOwlClassId() {
URI valueClass = propertyConstraint==null ? null : RdfUtil.uri( propertyConstraint.getValueClass() );
if (valueClass != null) {
return valueClass;
}
if (valueShape != null) {
return valueShape.getOwlClass().getId();
}
ShowlClass range = property.getRange();
return range == null ? null : range.getId();
}
public ShowlDerivedPropertyShape asDerivedPropertyShape() {
return null;
}
public ShowlNodeShape getDeclaringShape() {
return declaringShape;
}
public ShowlProperty getProperty() {
return property;
}
public URI getPredicate() {
return property.getPredicate();
}
public PropertyConstraint getPropertyConstraint() {
return propertyConstraint;
}
public boolean isNestedAccordingToFormula() {
if (propertyConstraint != null) {
QuantifiedExpression formula = propertyConstraint.getFormula();
if (formula != null) {
PrimaryExpression primary = formula.asPrimaryExpression();
if (primary instanceof PathExpression) {
PathExpression path = (PathExpression) primary;
int count = 0;
for (PathStep step : path.getStepList()) {
if (step instanceof DirectionStep) {
if (++count==2) {
return true;
}
}
}
}
}
}
return false;
}
public String fullPath() {
List stepList = new ArrayList<>();
ShowlPropertyShape p = this;
while (p != null) {
stepList.add(p.getPredicate().getLocalName());
ShowlNodeShape node = p.getDeclaringShape();
p = node.getAccessor();
if (p == null) {
p = node.getTargetProperty();
if ( p != null) {
p = p.getDeclaringShape().getAccessor();
} else {
node = node.getTargetNode();
if (node != null) {
p = node.getAccessor();
if (p != null) {
p = p.getDeclaringShape().getAccessor();
}
}
}
}
}
Collections.reverse(stepList);
StringBuilder builder = new StringBuilder();
String dot = "";
for (String fieldName : stepList) {
builder.append(dot);
builder.append(fieldName);
dot = ".";
}
return builder.toString();
}
@Override
public String getPath() {
List elements = new ArrayList<>();
ShowlNodeShape node = null;
for (ShowlPropertyShape p=this; p!=null; p=node.getAccessor()) {
elements.add(p);
node = p.getDeclaringShape();
}
StringBuilder builder = new StringBuilder();
builder.append('{');
builder.append(RdfUtil.localName(node.getShape().getId()));
builder.append('}');
for (int i=elements.size()-1; i>=0; i--) {
ShowlPropertyShape p = elements.get(i);
builder.append(p.pathSeparator());
builder.append(p.getPredicate().getLocalName());
}
return builder.toString();
}
public String toString() {
return getPath();
}
public ShowlNodeShape getValueShape() {
return valueShape;
}
public void setValueShape(ShowlNodeShape valueShape) {
this.valueShape = valueShape;
}
public ShowlNodeShape getRootNode() {
ShowlNodeShape root = declaringShape;
while (root.getAccessor() != null) {
root = root.getAccessor().getDeclaringShape();
}
return root;
}
public URI getValueType(OwlReasoner reasoner) {
if (Konig.id.equals(getPredicate())) {
return getDeclaringShape().getOwlClass().getId();
}
if (propertyConstraint != null) {
if (propertyConstraint.getDatatype() != null) {
return propertyConstraint.getDatatype();
}
URI valueClass = RdfUtil.uri(propertyConstraint.getValueClass());
if (valueClass == null) {
Shape shape = propertyConstraint.getShape();
if (shape != null) {
valueClass = shape.getTargetClass();
}
}
if (valueClass != null) {
return valueClass;
}
}
return property.inferRange(reasoner);
}
public ShowlClass getValueType(ShowlSchemaService schemaService) {
if (propertyConstraint != null) {
URI valueClass = RdfUtil.uri(propertyConstraint.getValueClass());
if (valueClass == null) {
Shape shape = propertyConstraint.getShape();
if (shape != null) {
valueClass = shape.getTargetClass();
}
}
if (valueClass != null) {
return schemaService.produceShowlClass(valueClass);
}
}
return property.inferRange(schemaService);
}
/**
* Returns the Property Shape linked to this one via a Formula.
* The link connects the PropertyShape that declares the Formula to the tail of the path in the formula.
*/
public ShowlPropertyShape getPeer() {
return peerGroup.size()==1 ? peerGroup.iterator().next() : null;
}
/**
* Sets the Property Shape linked to this one via a Formula, and visa versa.
* The link connects the PropertyShape that declares the Formula to the tail of the path in the formula.
*
*/
void addPeer(ShowlPropertyShape peer) {
if (logger.isDebugEnabled()) {
logger.debug("addPeer: {} <=> {}", this.getPath(), peer.getPath());
}
peerGroup.add(peer);
peer.peerGroup.add(this);
}
public Set getPeerGroup() {
return peerGroup;
}
public void addJoinCondition(ShowlJoinCondition join) {
if (joinConditions == null) {
joinConditions = new HashMap<>();
}
ShowlPropertyShape other = join.otherProperty(this);
if (other != null) {
joinConditions.put(other, join);
} else {
throw new IllegalArgumentException();
}
}
/**
* Check whether there exists a join condition involving this property and some other property.
* @param otherProperty The other property in the join condition.
* @return The join condition if one exists; otherwise return null.
*/
public ShowlJoinCondition findJoinCondition(ShowlPropertyShape otherProperty) {
return joinConditions==null ? null : joinConditions.get(otherProperty);
}
public char pathSeparator() {
return '.';
}
public Direction getDirection() {
return Direction.OUT;
}
public ShowlMapping getSelectedMapping() {
return selectedMapping;
}
public void setSelectedMapping(ShowlMapping selectedMapping) {
this.selectedMapping = selectedMapping;
}
public Set getHasValueDeprecated() {
return hasValueDeprecated==null ? Collections.emptySet() : hasValueDeprecated;
}
public void addHasValueDeprecated(Value value) {
if (hasValueDeprecated == null) {
hasValueDeprecated = new LinkedHashSet<>();
}
hasValueDeprecated.add(value);
}
public List getExpressionList() {
return expressionList;
}
public void addExpression(ShowlExpression expression) {
if (logger.isTraceEnabled()) {
logger.trace("{}.addExpression({})", getPath(), expression.displayValue());
}
expressionList.add(expression);
}
public boolean isDeclaredWithin(ShowlNodeShape node) {
for (ShowlNodeShape parent=declaringShape;
parent!=null;
parent = parent.getAccessor()==null ? null : parent.getAccessor().getDeclaringShape()) {
if (parent == node) {
return true;
}
}
return false;
}
public boolean inSameNodeShape(ShowlPropertyShape other) {
return other.isDeclaredWithin(declaringShape) || isDeclaredWithin(other.getDeclaringShape());
}
/*
* We ought to rethink how we handle synonyms. This ought to return a set of properties since
* in theory there might be many synonyms.
*/
public ShowlPropertyShape getSynonym() {
for (ShowlExpression e : expressionList) {
if (e instanceof ShowlPropertyExpression) {
ShowlPropertyShape other = ((ShowlPropertyExpression) e).getSourceProperty();
if (inSameNodeShape(other)) {
return other;
}
}
}
return null;
}
public Set synonyms() {
Set set = new HashSet<>();
addSynonym(set, this);
return set;
}
private void addSynonym(Set set, ShowlPropertyShape p) {
if (!set.contains(p)) {
set.add(p);
ShowlExpression formula = p.getFormula();
if (formula instanceof ShowlPropertyExpression) {
ShowlPropertyShape q = ((ShowlPropertyExpression) formula).getSourceProperty();
set.add(q);
}
for (ShowlExpression e : p.getExpressionList()) {
if (e instanceof ShowlPropertyExpression) {
ShowlPropertyShape other = ((ShowlPropertyExpression) e).getSourceProperty();
if (inSameNodeShape(other)) {
addSynonym(set, other);
}
}
}
}
}
public List propertyPath() {
List list = new ArrayList<>();
for (ShowlPropertyShape p = this; p!=null; p=p.getDeclaringShape().getAccessor()) {
list.add(p);
}
Collections.reverse(list);
return list;
}
public ShowlDirectPropertyShape direct() {
ShowlPropertyShape maybe = maybeDirect();
return maybe instanceof ShowlDirectPropertyShape ? (ShowlDirectPropertyShape) maybe : null;
}
/**
* Return the synonym of this property if the synonym is direct. Otherwise, return this property.
*/
public ShowlPropertyShape maybeDirect() {
if (this instanceof ShowlDirectPropertyShape) {
return this;
}
ShowlPropertyShape synonym = getSynonym();
if (synonym instanceof ShowlDirectPropertyShape) {
return synonym;
}
return this;
}
public ShowlExpression getFormula() {
return formula;
}
public void setFormula(ShowlExpression formula) {
this.formula = formula;
}
/**
* Get the expression that was selected to construct the value for this property.
*/
public ShowlExpression getSelectedExpression() {
return selectedExpression;
}
/**
* Set the expression that was selected to construct the value for this property.
*/
public void setSelectedExpression(ShowlExpression selectedExpression) {
if (selectedExpression!=null && logger.isTraceEnabled()) {
logger.trace("setSelectedExpression {} = {}", getPath(), selectedExpression.displayValue());
System.out.print("");
}
this.selectedExpression = selectedExpression;
}
/**
* The set of 'selected' expressions in which this property appears.
* A 'selected' expression is one that is used in the mapping from source to target.
* If this set is non-empty, then it must be the case that this property is a source property.
*/
public Set getUsedIn() {
return usedIn==null ? Collections.emptySet() : usedIn;
}
/**
* Declared that this property appears in a given selected expression.
*/
public void usedIn(ShowlExpression e) {
if (usedIn == null) {
usedIn = new LinkedHashSet<>();
}
usedIn.add(e);
}
public void addHasValue(ShowlExpression e) {
if (hasValue == null) {
hasValue = new LinkedHashSet<>();
}
hasValue.add(e);
}
public Set getHasValue() {
return hasValue == null ? Collections.emptySet() : hasValue;
}
public boolean isEnumIndividual() {
return getSelectedExpression() instanceof ShowlEnumNodeExpression;
}
public boolean isEnumProperty(OwlReasoner reasoner) {
return ShowlUtil.isEnumSourceNode(getDeclaringShape(), reasoner);
}
public boolean isTargetProperty() {
ShowlNodeShape node = getDeclaringShape();
if (node.getTargetNode()!=null || node.getTargetProperty()!=null) {
return false;
}
ShowlNodeShape root = getRootNode();
if (root.getTargetNode()!=null || node.getTargetProperty()!=null) {
return false;
}
return true;
}
public boolean isUniqueKey() {
ShowlPropertyShape peer = maybeDirect();
PropertyConstraint constraint = peer.getPropertyConstraint();
if (constraint != null) {
return Konig.uniqueKey.equals(constraint.getStereotype());
}
return false;
}
public ShowlPropertyShapeGroup asGroup() {
ShowlEffectiveNodeShape node = getDeclaringShape().effectiveNode();
return node.findPropertyByPredicate(getPredicate());
}
public SynsetProperty asSynsetProperty() {
SynsetNode node = getDeclaringShape().synsetNode();
return node.findPropertyByPredicate(getPredicate());
}
public ShowlPropertyShapeGroup getTargetProperty() {
return targetProperty;
}
public void setTargetProperty(ShowlPropertyShapeGroup targetProperty) {
this.targetProperty = targetProperty;
}
public boolean isRepeated() {
return propertyConstraint != null && propertyConstraint.getMaxCount()==null;
}
}