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 org.apache.jena.graph.Graph; 023import org.apache.jena.graph.Triple; 024import org.apache.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 org.apache.jena.graph.Node.ANY; 030import static org.apache.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 synchronized (this) { 073 if (notCommon.contains(x)) { 074 notCommon.remove(x.getSubject(), x.getPredicate(), x.getObject()); 075 common.add(x); 076 } else if (!common.contains(x)) { 077 source.accept(x); 078 } 079 } 080 }); 081 } 082 083 /** 084 * This method returns the difference between the two input sources. 085 * 086 * @return The differences between the two inputs. 087 */ 088 public Stream<Triple> difference() { 089 return source.build(); 090 } 091 092 /** 093 * This method will return null until the source iterator is exhausted. 094 * 095 * @return The elements that turned out to be common to the two inputs. 096 */ 097 public Stream<Triple> common() { 098 return stream(spliteratorUnknownSize(common.find(ANY, ANY, ANY), IMMUTABLE), false); 099 } 100 101 /** 102 * This method will return null until the source iterator is exhausted. 103 * 104 * @return The elements that turned out not to be common to the two inputs. 105 */ 106 public Stream<Triple> notCommon() { 107 return stream(spliteratorUnknownSize(notCommon.find(ANY, ANY, ANY), IMMUTABLE), false); 108 } 109}