Search in sources :

Example 1 with PropertyShape

use of org.apache.jena.shacl.parser.PropertyShape in project webofneeds by researchstudio-sat.

the class MainTypesPostprocessor method configureTypeWithNodeShapes.

private void configureTypeWithNodeShapes(TypeSpec.Builder typeBuilder, String name, Set<Shape> relevantShapes, Shapes shapes, Shacl2JavaConfig config) {
    // first,prepare a methodbuilder for the toRdf method
    // we will add statements to it while processing the relevant shapes
    MethodSpec.Builder toRdfBuilderDelegating = MethodSpec.methodBuilder("toRdf").addModifiers(PUBLIC).addAnnotation(Override.class).addParameter(ParameterizedTypeName.get(Consumer.class, Triple.class), "tripleConsumer").addStatement("toRdf(tripleConsumer, true)");
    typeBuilder.addMethod(toRdfBuilderDelegating.build());
    MethodSpec.Builder toRdfBuilder = MethodSpec.methodBuilder("toRdf").addModifiers(PUBLIC).addParameter(ParameterizedTypeName.get(Consumer.class, Triple.class), "tripleConsumer").addParameter(ClassName.BOOLEAN, "includeIndividuals").addStatement("$T obj = null", Node.class).addStatement("$T entityNode = getNodeCreateIfNecessary()", Node.class).beginControlFlow("if (getGraph() == null)").addStatement("additionalTriplesToRdf(tripleConsumer)");
    generateRequiredRdfTypeStatements(toRdfBuilder, relevantShapes);
    // we want each type to have a .builder() method returning a builder for the
    // type
    TypeName typeName = ClassName.get(config.getPackageName(), name);
    ClassName builderTypeName = ClassName.get(config.getPackageName(), name + ".Builder");
    TypeSpec.Builder builderBuilder = generateBuilderBuilder(typeBuilder, typeName, builderTypeName);
    // for the clone() method, we prepare another builder
    // we will add statements to it while processing the relevant shapes
    MethodSpec.Builder cloneBuilder = MethodSpec.methodBuilder("clone").addModifiers(PUBLIC).returns(ClassName.OBJECT).addAnnotation(Override.class).addStatement("$T clone = ($T) super.clone()", typeName, typeName);
    for (Shape relevantShape : relevantShapes) {
        Set<PropertyShape> propertyShapes = new HashSet();
        propertyShapes.addAll(relevantShape.getPropertyShapes());
        propertyShapes.addAll(ShapeUtils.getShPropertyShapes(relevantShape));
        // remember all fields we generate for the same path for this type, so we can
        // add a common interface
        // and a getter for the union of all these fields:
        Map<Path, Set<FieldSpec>> fieldsPerPath = new HashMap<>();
        Map<Path, Set<PropertySpec>> propSpecsPerPath = propertyShapes.stream().collect(Collectors.toMap(s -> s.getPath(), s -> (Set<PropertySpec>) ShapeUtils.getPropertySpecs(s), (left, right) -> {
            Set union = new HashSet(left);
            union.addAll(right);
            return union;
        }));
        for (Path path : propSpecsPerPath.keySet()) {
            Optional<String> propertyName = NameUtils.propertyNameForPath(path);
            if (!propertyName.isPresent()) {
                continue;
            }
            logger.debug("generating property '{}' of {}", propertyName.get(), NameUtils.nameForShape(relevantShape));
            Set<PropertySpec> propertySpecs = propSpecsPerPath.get(path);
            if (logger.isDebugEnabled()) {
                for (PropertySpec propertySpec : propertySpecs) {
                    logger.debug("\tfound property spec: {}", propertySpec);
                }
            }
            boolean addTypeSuffix = propertySpecs.size() > 1;
            for (PropertySpec propertySpec : propertySpecs) {
                addFieldWithPropertySpec(shapes, propertyName.get(), path, propertySpec, typeBuilder, builderBuilder, builderTypeName, toRdfBuilder, cloneBuilder, fieldsPerPath, config, addTypeSuffix);
            }
        }
        // add union getter
        fieldsPerPath.entrySet().stream().forEach(pathToFields -> {
            Set<FieldSpec> fieldSpecs = pathToFields.getValue();
            if (fieldSpecs.size() < 2) {
                return;
            }
            Path path = pathToFields.getKey();
            Optional<String> fieldName = propertyNameForPath(path);
            if (fieldName.isPresent()) {
                addUnionGetter(fieldName.get(), path, typeBuilder, fieldSpecs, config);
            }
        });
    }
    // 
    relevantShapes.stream().flatMap(s -> checkShapeForIndividuals(s).stream()).collect(Collectors.toMap(s -> new Object[] { s.getPredicate(), s.getClassName() }, s -> s, (left, right) -> IndividualPropertySpec.merge(left, right))).values().stream().forEach(spec -> addFieldWithIndividualPropertySpec(spec, typeBuilder, toRdfBuilder, cloneBuilder, config));
    // finish toRdf method
    toRdfBuilder.nextControlFlow("else").addStatement("super.toRdf(tripleConsumer)").endControlFlow();
    // finish clone method
    cloneBuilder.addStatement("return clone");
    typeBuilder.addType(builderBuilder.build());
    typeBuilder.addMethod(toRdfBuilder.build());
    typeBuilder.addMethod(cloneBuilder.build());
}
Also used : PropertyPath(won.shacl2java.annotation.PropertyPath) PathVisitorBase(org.apache.jena.sparql.path.PathVisitorBase) RDF(org.apache.jena.vocabulary.RDF) java.util(java.util) com.squareup.javapoet(com.squareup.javapoet) BuildableClassNames(won.shacl2java.sourcegen.typegen.mapping.BuildableClassNames) Modifier(javax.lang.model.element.Modifier) LoggerFactory(org.slf4j.LoggerFactory) org.apache.jena.graph(org.apache.jena.graph) ShapeTargetClasses(won.shacl2java.sourcegen.typegen.mapping.ShapeTargetClasses) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) P_Link(org.apache.jena.sparql.path.P_Link) Path(org.apache.jena.sparql.path.Path) ShapeUtils(won.shacl2java.util.ShapeUtils) ToRdfUtils(won.shacl2java.runtime.ToRdfUtils) TypesPostprocessor(won.shacl2java.sourcegen.typegen.TypesPostprocessor) IndividualPropertySpec(won.shacl2java.sourcegen.typegen.support.IndividualPropertySpec) ClassConstraint(org.apache.jena.shacl.engine.constraint.ClassConstraint) Shape(org.apache.jena.shacl.parser.Shape) NameUtils(won.shacl2java.util.NameUtils) URI(java.net.URI) Method(java.lang.reflect.Method) TypeSpecNames(won.shacl2java.sourcegen.typegen.mapping.TypeSpecNames) PropertySpec(won.shacl2java.constraints.PropertySpec) P_Inverse(org.apache.jena.sparql.path.P_Inverse) Logger(org.slf4j.Logger) SHACL(org.apache.jena.shacl.vocabulary.SHACL) MethodHandles(java.lang.invoke.MethodHandles) CLASS(com.squareup.javapoet.TypeSpec.Kind.CLASS) ShapeTypeSpecs(won.shacl2java.sourcegen.typegen.mapping.ShapeTypeSpecs) CollectionUtils(won.shacl2java.util.CollectionUtils) Collectors(java.util.stream.Collectors) Consumer(java.util.function.Consumer) TypegenUtils(won.shacl2java.sourcegen.typegen.support.TypegenUtils) Individual(won.shacl2java.annotation.Individual) Literal(org.apache.jena.rdf.model.Literal) ProducerConsumerMap(won.shacl2java.sourcegen.typegen.support.ProducerConsumerMap) Shacl2JavaConfig(won.shacl2java.Shacl2JavaConfig) RDFDatatype(org.apache.jena.datatypes.RDFDatatype) Shapes(org.apache.jena.shacl.Shapes) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) Shape(org.apache.jena.shacl.parser.Shape) IndividualPropertySpec(won.shacl2java.sourcegen.typegen.support.IndividualPropertySpec) PropertySpec(won.shacl2java.constraints.PropertySpec) PropertyPath(won.shacl2java.annotation.PropertyPath) Path(org.apache.jena.sparql.path.Path)

Example 2 with PropertyShape

use of org.apache.jena.shacl.parser.PropertyShape in project jena by apache.

the class VLib method validateShape.

public static void validateShape(ValidationContext vCxt, Graph data, Shape shape, Node focusNode) {
    if (shape.deactivated())
        return;
    if (vCxt.isVerbose())
        out.println("S: " + shape);
    Path path;
    Set<Node> vNodes;
    if (shape instanceof NodeShape) {
        path = null;
        vNodes = null;
    } else if (shape instanceof PropertyShape) {
        PropertyShape propertyShape = (PropertyShape) shape;
        path = propertyShape.getPath();
        vNodes = ShaclPaths.valueNodes(data, focusNode, propertyShape.getPath());
    } else {
        if (vCxt.isVerbose())
            out.println("Z: " + shape);
        return;
    }
    // Constraints of this shape.
    for (Constraint c : shape.getConstraints()) {
        if (vCxt.isVerbose())
            out.println("C: " + c);
        evalConstraint(vCxt, data, shape, focusNode, path, vNodes, c);
    }
    // Reachable shapes.
    // Follow sh:property (sh:node behaves as a constraint).
    validationPropertyShapes(vCxt, data, shape.getPropertyShapes(), focusNode);
    if (vCxt.isVerbose())
        out.println();
}
Also used : Path(org.apache.jena.sparql.path.Path) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) Constraint(org.apache.jena.shacl.parser.Constraint) Node(org.apache.jena.graph.Node) NodeShape(org.apache.jena.shacl.parser.NodeShape)

Example 3 with PropertyShape

use of org.apache.jena.shacl.parser.PropertyShape in project webofneeds by researchstudio-sat.

the class Shacl2JavaInstanceFactory method instantiate.

/**
 * Creates all instances for the given node / shape combination.
 *
 * @param node may be null, in which case all target nodes of the shape are
 * chosen.
 * @param shape
 * @return the set of nodes reached during instantiation that have not been
 * instantiated yet
 */
private Set<DataNodeAndShapes> instantiate(Node node, Shape shape, boolean forceApplyShape, InstantiationContext ctx) {
    if (shape.getShapeNode().isBlank()) {
        if (node == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Not instantiating entity for shape {}", shape.getShapeNode().getBlankNodeLabel());
            }
        } else {
            throw new IllegalArgumentException(String.format("Cannot instantiate entity for node %s: shape %s is a blank node", node.getLocalName(), shape.getShapeNode().getBlankNodeLabel()));
        }
    }
    Collection<Node> focusNodes;
    if (node != null) {
        if (!forceApplyShape) {
            if (!isFocusNode(shape, node, ctx.getData())) {
                return Collections.emptySet();
            }
        }
        if (ctx.hasInstanceForFocusNode(node) && !ctx.isNewShapeForFocusNode(node, shape)) {
            return Collections.emptySet();
        }
        if (logger.isDebugEnabled()) {
            logger.debug("processing node {} with shape {}", node, shape);
        }
        focusNodes = Collections.singleton(node);
    } else {
        focusNodes = focusNodes(ctx.getData(), shape);
    }
    if (focusNodes.isEmpty()) {
        return Collections.emptySet();
    }
    final Set<Node> finalFocusNodes = removeNodesInstantiatedInBaseContext(focusNodes).stream().filter(fnode -> {
        // check if focusnode conforms to shape
        ValidationContext vCtx = ctx.newValidationContext();
        VLib.validateShape(vCtx, ctx.getData(), shape, fnode);
        if (vCtx.hasViolation()) {
            if (logger.isDebugEnabled()) {
                logger.debug("skipping node {} as it does not conform to shape {}", fnode, shape.getShapeNode());
            }
            return false;
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("accepting node {} as it conforms to shape {}", fnode, shape.getShapeNode());
            }
        }
        return true;
    }).collect(Collectors.toSet());
    String shapeURI = shape.getShapeNode().getURI();
    Set<Class<?>> classesForShape = ctx.getClassesForShape(shapeURI);
    if (classesForShape == null) {
        if (logger.isDebugEnabled()) {
            logger.debug("No class found to instantiate for shape {}.", shape.getShapeNode().getLocalName());
            logger.debug("Instantiation context:");
            logger.debug(ctx.getFormattedState());
        }
        throw new IllegalArgumentException(String.format("No class found to instantiate for shape %s, more information is logged on loglevel debug", shape.getShapeNode().getLocalName()));
    }
    Set ret = classesForShape.stream().map(classForShape -> {
        // our shape might reference other shapes via sh:node (maybe through other
        // operators such as sh:or)
        // * we remember them for wiring
        // * we return them as dependencies to instantiate
        Set<Shape> allRelevantShapes = ShapeUtils.getNodeShapes((NodeShape) shape, shapes);
        Map<Path, Set<PropertyShape>> propertyShapesPerPath = getPropertyShapesByPath(allRelevantShapes);
        allRelevantShapes.add(shape);
        return finalFocusNodes.parallelStream().map(focusNode -> {
            try {
                Object instance = null;
                if (logger.isDebugEnabled()) {
                    logger.debug("attempting to instantiate focus node {} with shape {}", focusNode, shape.getShapeNode());
                }
                instance = instantiate(shape, shapeURI, focusNode, classForShape, ctx);
                if (instance == null) {
                    // maybe another shape works better
                    return Collections.emptySet();
                }
                ctx.addInstanceForFocusNode(focusNode, instance);
                ctx.setFocusNodeForInstance(instance, focusNode);
                ctx.setClassForInstance(instance, classForShape);
                ctx.addShapesForFocusNode(focusNode, allRelevantShapes);
            } catch (NoSuchMethodException e) {
                throw new IllegalArgumentException(String.format("Cannot instantiate %s for shape %s", classForShape.getName(), shape.getShapeNode().getLocalName()) + ": no parameterless constructor found", e);
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
                throw new IllegalArgumentException(String.format("Cannot instantiate %s for shape %s - %s: %s", classForShape.getName(), shape.getShapeNode().getLocalName(), e.getClass().getSimpleName(), e.getMessage()), e);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Collecting dependencies of focus node {}", focusNode);
            }
            return propertyShapesPerPath.entrySet().parallelStream().map(pathToShapes -> {
                Path path = pathToShapes.getKey();
                Set<PropertyShape> propertyShapes = pathToShapes.getValue();
                if (logger.isDebugEnabled()) {
                    logger.debug("\tcollecting new focus nodes via path {} ", path);
                }
                Set<Node> valueNodes = ShaclPaths.valueNodes(ctx.getData(), focusNode, path);
                if (valueNodes.isEmpty()) {
                    return Collections.emptySet();
                }
                return valueNodes.stream().map(valueNode -> propertyShapes.stream().map(ctx::getNodeShapesForPropertyShape).map(nodeShapeNodes -> new DataNodeAndShapes(valueNode, nodeShapeNodes)).collect(Collectors.toSet())).reduce(CollectionUtils::union).orElse(Collections.emptySet());
            }).reduce(CollectionUtils::union).orElse(Collections.emptySet());
        }).reduce(CollectionUtils::union).orElse(Collections.emptySet());
    }).reduce(CollectionUtils::union).orElse(Collections.emptySet());
    return ret;
}
Also used : PropertyPath(won.shacl2java.annotation.PropertyPath) java.util(java.util) NodeFactory(org.apache.jena.graph.NodeFactory) PathParser(org.apache.jena.sparql.path.PathParser) InstantiationContext(won.shacl2java.instantiation.InstantiationContext) ValidationContext(org.apache.jena.shacl.engine.ValidationContext) LoggerFactory(org.slf4j.LoggerFactory) Graph(org.apache.jena.graph.Graph) NameUtils.setterNameForField(won.shacl2java.util.NameUtils.setterNameForField) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) Path(org.apache.jena.sparql.path.Path) NameUtils.adderNameForFieldNameInPlural(won.shacl2java.util.NameUtils.adderNameForFieldNameInPlural) ShapeUtils(won.shacl2java.util.ShapeUtils) Shape(org.apache.jena.shacl.parser.Shape) StreamSupport(java.util.stream.StreamSupport) NameUtils(won.shacl2java.util.NameUtils) URI(java.net.URI) NodeShape(org.apache.jena.shacl.parser.NodeShape) java.lang.reflect(java.lang.reflect) Logger(org.slf4j.Logger) VLib.focusNodes(org.apache.jena.shacl.validation.VLib.focusNodes) MethodHandles(java.lang.invoke.MethodHandles) PrefixMapping(org.apache.jena.shared.PrefixMapping) Individuals(won.shacl2java.annotation.Individuals) CollectionUtils(won.shacl2java.util.CollectionUtils) Collectors(java.util.stream.Collectors) ShaclPaths(org.apache.jena.shacl.engine.ShaclPaths) VLib(org.apache.jena.shacl.validation.VLib) DerivedInstantiationContext(won.shacl2java.instantiation.DerivedInstantiationContext) ShapeNode(won.shacl2java.annotation.ShapeNode) GraphEntity(won.shacl2java.runtime.model.GraphEntity) Stream(java.util.stream.Stream) VLib.isFocusNode(org.apache.jena.shacl.validation.VLib.isFocusNode) Individual(won.shacl2java.annotation.Individual) DataNodeAndShapes(won.shacl2java.instantiation.DataNodeAndShapes) Node(org.apache.jena.graph.Node) io.github.classgraph(io.github.classgraph) Shapes(org.apache.jena.shacl.Shapes) GraphFactory(org.apache.jena.sparql.graph.GraphFactory) PropertyPath(won.shacl2java.annotation.PropertyPath) Path(org.apache.jena.sparql.path.Path) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) Shape(org.apache.jena.shacl.parser.Shape) NodeShape(org.apache.jena.shacl.parser.NodeShape) ShapeNode(won.shacl2java.annotation.ShapeNode) VLib.isFocusNode(org.apache.jena.shacl.validation.VLib.isFocusNode) Node(org.apache.jena.graph.Node) DataNodeAndShapes(won.shacl2java.instantiation.DataNodeAndShapes) ValidationContext(org.apache.jena.shacl.engine.ValidationContext)

Example 4 with PropertyShape

use of org.apache.jena.shacl.parser.PropertyShape in project webofneeds by researchstudio-sat.

the class Shacl2JavaInstanceFactory method wireDependencies.

private void wireDependencies(Object instance, InstantiationContext ctx) {
    Map<Path, Set<Field>> fieldsByPath = new HashMap<>();
    Class<?> type = instance.getClass();
    Field[] instanceFields = type.getDeclaredFields();
    for (Field field : instanceFields) {
        extractPath(fieldsByPath, field);
        wireIndividuals(instance, field, ctx);
    }
    Node focusNode = ctx.getFocusNodeForInstance(instance);
    if (focusNode == null) {
        if (logger.isDebugEnabled()) {
            logger.debug("No focus node found for instance {}", instance);
        }
        return;
    }
    Set<Shape> shapesForFocusNode = ctx.getShapesForFocusNode(focusNode);
    if (shapesForFocusNode == null) {
        if (logger.isDebugEnabled()) {
            logger.debug("No shapes found for focus node {}", focusNode);
        }
        return;
    }
    Set<Path> pathsFromPropertyShapes = ctx.getShapesForFocusNode(focusNode).stream().flatMap(s -> s.getPropertyShapes().stream()).map(PropertyShape::getPath).collect(Collectors.toSet());
    pathsFromPropertyShapes.parallelStream().forEach(path -> {
        Set<Node> valueNodes = ShaclPaths.valueNodes(ctx.getData(), focusNode, path);
        Set<Field> fieldsForPath = fieldsByPath.get(path);
        if (fieldsForPath != null && !fieldsForPath.isEmpty()) {
            if (valueNodes.size() > 0) {
                for (Node valueNode : valueNodes) {
                    Set<Object> dependencyCandidates = ctx.getInstancesForFocusNode(valueNode);
                    if (dependencyCandidates == null) {
                        dependencyCandidates = new HashSet<>();
                    }
                    // covered by a shape
                    if (valueNode.isLiteral()) {
                        dependencyCandidates.add(valueNode.getLiteralDatatype().parse(valueNode.getLiteralLexicalForm()));
                    } else if (valueNode.isURI()) {
                        dependencyCandidates.add(URI.create(valueNode.getURI()));
                    }
                    Field field = null;
                    try {
                        SatisfiedFieldDependency fieldDependency = selectFieldByType(fieldsForPath, instance, dependencyCandidates);
                        if (fieldDependency == null) {
                            throw new IllegalArgumentException(makeWiringErrorMessage(instance, focusNode, dependencyCandidates, null, null) + ": unable to identify appropriate field to set");
                        }
                        field = fieldDependency.getField();
                        Object dependency = fieldDependency.getDependency();
                        setDependency(instance, field.getName(), dependency);
                        if (logger.isDebugEnabled()) {
                            logger.debug("wired {} ", makeWiringMessage(instance, focusNode, dependency, field));
                        }
                    } catch (Throwable e) {
                        throw new IllegalArgumentException(makeWiringErrorMessage(instance, focusNode, dependencyCandidates, field, e), e);
                    }
                }
            }
        }
    });
}
Also used : PropertyPath(won.shacl2java.annotation.PropertyPath) Path(org.apache.jena.sparql.path.Path) PropertyShape(org.apache.jena.shacl.parser.PropertyShape) Shape(org.apache.jena.shacl.parser.Shape) NodeShape(org.apache.jena.shacl.parser.NodeShape) ShapeNode(won.shacl2java.annotation.ShapeNode) VLib.isFocusNode(org.apache.jena.shacl.validation.VLib.isFocusNode) Node(org.apache.jena.graph.Node) NameUtils.setterNameForField(won.shacl2java.util.NameUtils.setterNameForField)

Aggregations

PropertyShape (org.apache.jena.shacl.parser.PropertyShape)4 Path (org.apache.jena.sparql.path.Path)4 Node (org.apache.jena.graph.Node)3 NodeShape (org.apache.jena.shacl.parser.NodeShape)3 Shape (org.apache.jena.shacl.parser.Shape)3 PropertyPath (won.shacl2java.annotation.PropertyPath)3 MethodHandles (java.lang.invoke.MethodHandles)2 URI (java.net.URI)2 java.util (java.util)2 Collectors (java.util.stream.Collectors)2 Shapes (org.apache.jena.shacl.Shapes)2 VLib.isFocusNode (org.apache.jena.shacl.validation.VLib.isFocusNode)2 Logger (org.slf4j.Logger)2 LoggerFactory (org.slf4j.LoggerFactory)2 Individual (won.shacl2java.annotation.Individual)2 ShapeNode (won.shacl2java.annotation.ShapeNode)2 CollectionUtils (won.shacl2java.util.CollectionUtils)2 NameUtils (won.shacl2java.util.NameUtils)2 NameUtils.setterNameForField (won.shacl2java.util.NameUtils.setterNameForField)2 ShapeUtils (won.shacl2java.util.ShapeUtils)2