001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.api.utils;
019
020import java.util.stream.Stream;
021
022import com.hp.hpl.jena.graph.Graph;
023import com.hp.hpl.jena.graph.Triple;
024import com.hp.hpl.jena.rdf.model.Model;
025
026import static java.util.Spliterator.IMMUTABLE;
027import static java.util.Spliterators.spliteratorUnknownSize;
028import static java.util.stream.StreamSupport.stream;
029import static com.hp.hpl.jena.graph.Node.ANY;
030import static com.hp.hpl.jena.sparql.graph.GraphFactory.createDefaultGraph;
031
032/**
033 * A wrapping {@link Stream} that calculates two differences between a
034 * {@link Graph} A and a source Stream B. The differences are (A - (A ∩ B)) and
035 * (B - (A ∩ B)). The ordinary output of this stream is (B - (A ∩ B)), and
036 * after exhaustion, sets containing (A - (A ∩ B)) and (A ∩ B) are available.
037 *
038 * @author ajs6f
039 * @author acoburn
040 * @since Oct 24, 2013
041 */
042public class GraphDifferencer {
043
044    private Graph notCommon;
045
046    private Graph common;
047
048    private Stream.Builder<Triple> source = Stream.builder();
049
050    /**
051     * Diff a Model against a stream of triples
052     *
053     * @param replacement the replacement
054     * @param original the original
055     */
056    public GraphDifferencer(final Model replacement,
057                                     final Stream<Triple> original) {
058        this(replacement.getGraph(), original);
059    }
060
061    /**
062     * Diff a graph against a stream of triples
063     *
064     * @param replacement the replacement
065     * @param original the original
066     */
067    public GraphDifferencer(final Graph replacement,
068                                     final Stream<Triple> original) {
069        notCommon = replacement;
070        common = createDefaultGraph();
071        original.forEach(x -> {
072            if (notCommon.contains(x)) {
073                notCommon.remove(x.getSubject(), x.getPredicate(), x.getObject());
074                common.add(x);
075            } else if (!common.contains(x)) {
076                source.accept(x);
077            }
078        });
079    }
080
081    /**
082     * This method returns the difference between the two input sources.
083     *
084     * @return The differences between the two inputs.
085     */
086    public Stream<Triple> difference() {
087        return source.build();
088    }
089
090    /**
091     * This method will return null until the source iterator is exhausted.
092     *
093     * @return The elements that turned out to be common to the two inputs.
094     */
095    public Stream<Triple> common() {
096        return stream(spliteratorUnknownSize(common.find(ANY, ANY, ANY), IMMUTABLE), false);
097    }
098
099    /**
100     * This method will return null until the source iterator is exhausted.
101     *
102     * @return The elements that turned out not to be common to the two inputs.
103     */
104    public Stream<Triple> notCommon() {
105        return stream(spliteratorUnknownSize(notCommon.find(ANY, ANY, ANY), IMMUTABLE), false);
106    }
107}