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

com.metreeca.json.Frame Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2013-2022 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;

import com.metreeca.json.shifts.Path;

import org.eclipse.rdf4j.model.*;
import org.eclipse.rdf4j.model.vocabulary.*;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static com.metreeca.json.Values.*;
import static com.metreeca.json.shifts.Alt.alt;
import static com.metreeca.json.shifts.Seq.seq;

import static java.util.Collections.*;
import static java.util.stream.Collectors.*;

/**
 * Linked data frame.
 *
 * 

Describes a linked data graph centered on a focus value.

*/ public final class Frame { private static final Path Labels=alt( RDFS.LABEL, DC.TITLE, iri("http://schema.org/", "name") ); private static final Path Notes=alt( RDFS.COMMENT, DC.DESCRIPTION, iri("http://schema.org/", "description") ); public static Frame frame(final Value focus) { if ( focus == null ) { throw new NullPointerException("null focus"); } return new Frame(focus, emptyMap()); } public static Frame frame(final Value focus, final Map> traits) { if ( focus == null ) { throw new NullPointerException("null focus"); } return new Frame(focus, traits.entrySet().stream().collect(toMap( Entry::getKey, e -> unmodifiableSet(new LinkedHashSet<>(e.getValue())) ))); } public static Frame frame(final Value focus, final Collection model) { if ( focus == null ) { throw new NullPointerException("null focus"); } if ( model == null || model.stream().anyMatch(Objects::isNull) ) { throw new NullPointerException("null model or model statement"); } return frame(focus, model, value -> false); } private static Frame frame(final Value focus, final Collection model, final Predicate visited) { return new Frame(focus, visited.test(focus) || !focus.isResource() ? emptyMap() : Stream.>concat( model.stream() .filter(pattern(focus, null, null)) .map(s -> new SimpleImmutableEntry<>(s.getPredicate(), s.getObject())), model.stream() .filter(pattern(null, null, focus)) .filter(s -> !visited.test(s.getSubject())) .map(s -> new SimpleImmutableEntry<>(inverse(s.getPredicate()), s.getSubject())) ).collect(groupingBy(Entry::getKey, collectingAndThen( mapping(entry -> entry.getKey().equals(RDF.TYPE) ? frame(entry.getValue()) // don't follow inverse type links : frame(entry.getValue(), model, visited.or(focus::equals)), toSet() ), Collections::unmodifiableSet )))); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private final Value focus; private final Map> traits; private Frame(final Value focus, final Map> traits) { this.focus=focus; this.traits=unmodifiableMap(traits); } public boolean empty() { return traits.isEmpty(); } public int size() { return traits.size()+traits.values().stream() .flatMap(Collection::stream) .mapToInt(Frame::size) .sum(); } public Optional label() { return string(Labels); } public Optional notes() { return string(Notes); } /** * Retrieves the frame focus. * * @return the frame focus value. */ public Value focus() { return focus; } public Map> traits() { return traits; } public Stream model() { return traits.entrySet().stream().flatMap(trait -> { final IRI predicate=trait.getKey(); final Collection frames=trait.getValue(); return frames.stream().flatMap(frame -> { final Statement statement=traverse(predicate, direct -> statement((Resource)focus, direct, frame.focus), inverse -> statement((Resource)frame.focus, inverse, focus) ); return Stream.concat(Stream.of(statement), frame.model()); }); }); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Frame refocus(final IRI focus) { if ( focus == null ) { throw new NullPointerException("null focus"); } return frame(focus, model() .map(statement -> rewrite(this.focus, focus, statement)) .collect(toList()) ); } private Statement rewrite(final Value source, final IRI target, final Statement statement) { return statement( rewrite(source, target, statement.getSubject()), rewrite(source, target, statement.getPredicate()), rewrite(source, target, statement.getObject()) ); } private V rewrite(final Value source, final V target, final V value) { return value.equals(source) ? target : value; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional bool(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return bool(seq(predicate)); } public Optional bool(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return value(shift).flatMap(Values::bool); } public Frame bool(final IRI predicate, final Boolean bool) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return bool == null ? this : value(predicate, Values.literal(bool)); } public Frame bool(final IRI predicate, final Optional bool) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( bool == null ) { throw new NullPointerException("null bool"); } return bool.map(object -> value(predicate, Values.literal(object))).orElse(this); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional integer(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return integer(seq(predicate)); } public Optional integer(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return value(shift).flatMap(Values::integer); } public Stream integers(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return integers(seq(predicate)); } public Stream integers(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return values(shift).map(Values::integer).filter(Optional::isPresent).map(Optional::get); } public Frame integer(final IRI predicate, final Number integer) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return integer == null ? this : integers(predicate, Stream.of(integer)); } public Frame integer(final IRI predicate, final Optional integer) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( integer == null ) { throw new NullPointerException("null integer"); } return integer.map(object -> integers(predicate, Stream.of(object))).orElse(this); } public Frame integers(final IRI predicate, final Number... integers) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( integers == null ) { throw new NullPointerException("null integers"); } return integers.length == 0 ? this : integers(predicate, Arrays.stream(integers)); } public Frame integers(final IRI predicate, final Collection integers) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( integers == null ) { throw new NullPointerException("null integers"); } return integers.isEmpty() ? this : integers(predicate, integers.stream()); } public Frame integers(final IRI predicate, final Stream integers) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( integers == null ) { throw new NullPointerException("null integers"); } return values(predicate, integers.map(value -> value instanceof BigInteger ? (BigInteger)value : value instanceof BigDecimal ? ((BigDecimal)value).toBigInteger() : BigInteger.valueOf(value.longValue()) ).map(Values::literal)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional decimal(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return decimal(seq(predicate)); } public Optional decimal(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return value(shift).flatMap(Values::decimal); } public Stream decimals(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return decimals(seq(predicate)); } public Stream decimals(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return values(shift).map(Values::decimal).filter(Optional::isPresent).map(Optional::get); } public Frame decimal(final IRI predicate, final Number decimal) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return decimal == null ? this : decimals(predicate, Stream.of(decimal)); } public Frame decimal(final IRI predicate, final Optional decimal) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( decimal == null ) { throw new NullPointerException("null decimal"); } return decimal.map(object -> decimals(predicate, Stream.of(object))).orElse(this); } public Frame decimals(final IRI predicate, final Number... decimals) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( decimals == null ) { throw new NullPointerException("null decimals"); } return decimals.length == 0 ? this : decimals(predicate, Arrays.stream(decimals)); } public Frame decimals(final IRI predicate, final Collection decimals) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( decimals == null ) { throw new NullPointerException("null decimals"); } return decimals.isEmpty() ? this : decimals(predicate, decimals.stream()); } public Frame decimals(final IRI predicate, final Stream decimals) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( decimals == null ) { throw new NullPointerException("null decimals"); } return values(predicate, decimals.map(value -> value instanceof BigDecimal ? (BigDecimal)value : value instanceof BigInteger ? new BigDecimal((BigInteger)value) : BigDecimal.valueOf(value.doubleValue()) ).map(Values::literal)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional string(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return string(seq(predicate)); } public Optional string(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return value(shift).map(Value::stringValue); } public Stream strings(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return strings(seq(predicate)); } public Stream strings(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return values(shift).map(Value::stringValue); } public Frame string(final IRI predicate, final String string) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return string == null ? this : strings(predicate, Stream.of(string)); } public Frame string(final IRI predicate, final Optional string) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( string == null ) { throw new NullPointerException("null string"); } return string.map(object -> strings(predicate, Stream.of(object))).orElse(this); } public Frame strings(final IRI predicate, final String... strings) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( strings == null ) { throw new NullPointerException("null strings"); } return strings.length == 0 ? this : strings(predicate, Arrays.stream(strings)); } public Frame strings(final IRI predicate, final Collection strings) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( strings == null ) { throw new NullPointerException("null strings"); } return strings.isEmpty() ? this : strings(predicate, strings.stream()); } public Frame strings(final IRI predicate, final Stream strings) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( strings == null ) { throw new NullPointerException("null strings"); } return values(predicate, strings.map(Values::literal)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional value(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return values(predicate).findFirst(); } public Optional value(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return values(shift).findFirst(); } public Stream values(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return frames(predicate).map(frame -> frame.focus); } public Stream values(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return frames(shift).map(frame -> frame.focus); } public Frame value(final IRI predicate, final Value value) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return value == null ? this : values(predicate, Stream.of(value)); } public Frame value(final IRI predicate, final Optional value) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( value == null ) { throw new NullPointerException("null value"); } return value.map(object -> values(predicate, Stream.of(object))).orElse(this); } public Frame values(final IRI predicate, final Value... values) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( values == null ) { throw new NullPointerException("null values"); } return values.length == 0 ? this : values(predicate, Arrays.stream(values)); } public Frame values(final IRI predicate, final Collection values) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( values == null ) { throw new NullPointerException("null values"); } return values.isEmpty() ? this : values(predicate, values.stream()); } public Frame values(final IRI predicate, final Stream values) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( values == null ) { throw new NullPointerException("null values"); } return frames(predicate, values.map(value -> new Frame(value, emptyMap()))); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public Optional frame(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return frame(seq(predicate)); } public Optional frame(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return frames(shift).findFirst(); } public Stream frames(final IRI predicate) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return traits.getOrDefault(predicate, emptySet()).stream(); } public Stream frames(final Shift shift) { if ( shift == null ) { throw new NullPointerException("null shift"); } return shift.map(new ShiftEvaluator(this)); } public Frame frame(final IRI predicate, final Frame frame) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } return frame == null ? this : frames(predicate, Stream.of(frame)); } public Frame frame(final IRI predicate, final Optional frame) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( frame == null ) { throw new NullPointerException("null frame"); } return frame.map(object -> frames(predicate, Stream.of(object))).orElse(this); } public Frame frames(final IRI predicate, final Frame... frames) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( frames == null ) { throw new NullPointerException("null frames"); } return frames.length == 0 ? this : frames(predicate, Arrays.stream(frames)); } public Frame frames(final IRI predicate, final Collection frames) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( frames == null ) { throw new NullPointerException("null frames"); } return frames.isEmpty() ? this : frames(predicate, frames.stream()); } public Frame frames(final IRI predicate, final Stream frames) { if ( predicate == null ) { throw new NullPointerException("null predicate"); } if ( frames == null ) { throw new NullPointerException("null frames"); } if ( !focus.isResource() && direct(predicate) ) { throw new IllegalArgumentException(String.format( "direct predicate %s with focus %s", Values.format(predicate), Values.format(focus) )); } final Collection merged=unmodifiableSet(new LinkedHashSet<>(index(Stream.concat( traits.getOrDefault(predicate, emptySet()).stream(), frames.peek(frame -> { if ( !frame.focus.isResource() && !direct(predicate) ) { throw new IllegalArgumentException(String.format( "inverse predicate %s with value %s", Values.format(predicate), Values.format(focus) )); } }) )).values())); if ( merged.isEmpty() ) {return this;} else { final Map> extended=new LinkedHashMap<>(traits); extended.put(predicate, merged); return new Frame(focus, extended); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private Map index(final Stream frames) { return frames.collect(groupingBy(Frame::focus, LinkedHashMap::new, reducing(null, (x, y) -> x == null ? y : y == null ? x : new Frame(x.focus, merge(x.traits, y.traits)) ))); } private Map> merge( final Map> x, final Map> y ) { final Map> merged=new LinkedHashMap<>(x); y.forEach((predicate, frames) -> merged.compute(predicate, (key, value) -> value == null ? frames : merge(frames, value) )); return merged; } private Collection merge(final Collection x, final Collection y) { final Map merged=index(x.stream()); y.forEach(frame -> merged.compute(focus, (key, value) -> value == null ? frame : new Frame(frame.focus, merge(value.traits, frame.traits)) )); return unmodifiableSet(new LinkedHashSet<>(merged.values())); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public String format() { // !!! test/review final StringBuilder builder=new StringBuilder(Values.format(focus)); label().ifPresent(label -> builder.append(" : ").append(label)); notes().ifPresent(notes -> builder.append(" / ").append(notes)); if ( !traits.isEmpty() ) { builder.append(' ').append(traits.entrySet().stream() .map(this::format) .map(Values::indent) .collect(joining(",\n\t", "{\n\t", "\n}")) ); } return builder.toString(); } private String format(final Entry> trait) { return Values.format(trait.getKey())+" : "+format(trait.getValue()); } private String format(final Collection values) { return values.isEmpty() ? "[]" // unexpected : values.size() == 1 ? Values.format(values.iterator().next()) : values.stream() .map(Frame::format) .map(Values::indent) .collect(joining(",\n\t", "[\n\t", "\n]")); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public boolean equals(final Object object) { return this == object || object instanceof Frame && focus.equals(((Frame)object).focus) && traits.equals(((Frame)object).traits); } @Override public int hashCode() { return focus.hashCode() ^traits.hashCode(); } @Override public String toString() { return Values.format(focus) +label().map(l -> String.format(" : %s", clip(l))).orElse("") +notes().map(n -> String.format(" / %s", clip(n))).orElse("") +(traits.isEmpty() ? "" : String.format(" { [%d] }", size())); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy