All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metreeca.json.shapes.Field Maven / Gradle / Ivy

/*
 * Copyright © 2013-2021 Metreeca srl
 *
 * 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.
 */

package com.metreeca.json.shapes;

import com.metreeca.json.Shape;
import com.metreeca.json.Values;

import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.vocabulary.RDF;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static com.metreeca.json.shapes.All.all;
import static com.metreeca.json.shapes.And.and;
import static com.metreeca.json.shapes.Or.or;

import static java.lang.String.format;
import static java.util.Arrays.stream;
import static java.util.Collections.emptyMap;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;


/**
 * Field structural constraint.
 *
 * 

States that the derived focus set generated by traversing a single step path is consistent with a given {@link * Shape shape}.

*/ public final class Field extends Shape { private static final java.util.regex.Pattern LabelPattern=Pattern.compile( "\\w+" ); private static final Pattern NamedIRIPattern=Pattern.compile( "([/#:])(?"+LabelPattern+")(/|#|#_|#id|#this)?$" ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static Shape field(final IRI iri, final Shape... shapes) { if ( iri == null ) { throw new NullPointerException("null iri"); } if ( shapes == null || stream(shapes).anyMatch(Objects::isNull) ) { throw new NullPointerException("null shapes"); } return field("", iri, and(shapes)); } public static Shape field(final IRI iri, final Object... values) { if ( iri == null ) { throw new NullPointerException("null iri"); } if ( values == null || stream(values).anyMatch(Objects::isNull) ) { throw new NullPointerException("null values"); } return field("", iri, all(values)); } public static Shape field(final IRI iri, final Shape shape) { if ( iri == null ) { throw new NullPointerException("null iri"); } if ( shape == null ) { throw new NullPointerException("null shape"); } return field("", iri, shape); } public static Shape field(final String label, final IRI iri, final Shape... shapes) { if ( label == null ) { throw new NullPointerException("null label"); } if ( !(label.isEmpty() || LabelPattern.matcher(label).matches()) ) { throw new IllegalArgumentException(format("malformed label <%s>", label)); } if ( iri == null ) { throw new NullPointerException("null iri"); } if ( shapes == null || stream(shapes).anyMatch(Objects::isNull) ) { throw new NullPointerException("null shapes"); } return field(label, iri, and(shapes)); } public static Shape field(final String label, final IRI iri, final Object... values) { if ( label == null ) { throw new NullPointerException("null label"); } if ( !(label.isEmpty() || LabelPattern.matcher(label).matches()) ) { throw new IllegalArgumentException(format("malformed label <%s>", label)); } if ( iri == null ) { throw new NullPointerException("null iri"); } if ( values == null || stream(values).anyMatch(Objects::isNull) ) { throw new NullPointerException("null values"); } return field(label, iri, all(values)); } public static Shape field(final String label, final IRI iri, final Shape shape) { if ( label == null ) { throw new NullPointerException("null label"); } if ( iri == null ) { throw new NullPointerException("null iri"); } if ( shape == null ) { throw new NullPointerException("null shape"); } return shape.equals(or()) ? and() : new Field(label, iri, shape); } public static Stream fields(final Shape shape) { if ( shape == null ) { throw new NullPointerException("null shape"); } return shape.map(new FieldsProbe()); } public static Optional field(final Shape shape, final IRI iri) { if ( shape == null ) { throw new NullPointerException("null shape"); } if ( iri == null ) { throw new NullPointerException("null iri"); } return fields(shape) .filter(field -> field.iri().equals(iri)) .findFirst(); } public static Optional field(final Shape shape, final Collection path) { if ( shape == null ) { throw new NullPointerException("null shape"); } if ( path == null || path.stream().anyMatch(Objects::isNull) ) { throw new NullPointerException("null path"); } Optional field=null; for (final IRI step : path) { field=(field != null ? field.map(Field::shape) : Optional.of(shape)).flatMap(s -> field(s, step)); } return field != null ? field : Optional.empty(); } public static Map labels(final Shape shape) { if ( shape == null ) { throw new NullPointerException("null shape"); } return labels(shape, emptyMap()); } public static Map labels(final Shape shape, final Map keywords) { if ( shape == null ) { throw new NullPointerException("null shape"); } if ( keywords == null ) { throw new NullPointerException("null keywords"); } return fields(shape).collect(toMap( field -> { final IRI iri=field.iri(); final boolean direct=Values.direct(iri); if ( direct && iri.equals(RDF.TYPE) ) { return keywords.getOrDefault("@type", "@type"); } else { final String label=Optional.of(field.label()).filter(s -> !s.isEmpty()).orElseGet(() -> Optional .of(NamedIRIPattern.matcher(iri.stringValue())) .filter(Matcher::find) .map(matcher -> matcher.group("name")) .map(name -> direct ? name : name+"Of") .orElseThrow(() -> new IllegalArgumentException(format("undefined label for %s", iri)) ) ); if ( keywords.containsValue(label) ) { throw new IllegalArgumentException(format("reserved label <%s> for %s", label, iri)); } return label; } }, identity(), (x, y) -> { throw new IllegalArgumentException(format( "clashing labels for fields <%s>=%s / <%s>=%s", x.label(), x.iri(), y.label(), y.iri() )); }, LinkedHashMap::new )); } static Optional label(final String x, final String y) { return y.isEmpty() || x.equals(y) ? Optional.of(x) : x.isEmpty() ? Optional.of(y) : Optional.empty(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private final String label; private final IRI iri; private final Shape shape; Field(final String label, final IRI iri, final Shape shape) { this.label=label; this.iri=iri; this.shape=shape; } public String label() { return label; } public IRI iri() { return iri; } public Shape shape() { return shape; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public V map(final Probe probe) { if ( probe == null ) { throw new NullPointerException("null probe"); } return probe.probe(this); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public boolean equals(final Object object) { return this == object || object instanceof Field && label.equals(((Field)object).label) && iri.equals(((Field)object).iri) && shape.equals(((Field)object).shape); } @Override public int hashCode() { return label.hashCode() ^iri.hashCode() ^shape.hashCode(); } @Override public String toString() { final StringBuilder builder=new StringBuilder(25); builder.append("field("); if ( !label.isEmpty() ) { builder.append('\'').append(label).append("' = "); } builder.append('<').append(iri).append('>'); if ( !shape.equals(and()) ) { builder.append(", ").append(shape); } builder.append(")"); return builder.toString(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private static final class FieldsProbe extends Probe> { @Override public Stream probe(final Link link) { return link.shape().map(this); } @Override public Stream probe(final Field field) { return Stream.of(field); } @Override public Stream probe(final When when) { return Stream.of(when.pass(), when.fail()).flatMap(this); } @Override public Stream probe(final And and) { return and.shapes().stream().flatMap(shape -> shape.map(this)); } @Override public Stream probe(final Or or) { return or.shapes().stream().flatMap(shape -> shape.map(this)); } @Override public Stream probe(final Shape shape) { return Stream.empty(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy