/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 /////////////// package org.apache.jena.graph.compose; import java.util.Iterator ; import java.util.Set ; import org.apache.jena.JenaRuntime ; import org.apache.jena.graph.* ; import org.apache.jena.graph.impl.SimpleEventManager ; import org.apache.jena.shared.JenaException ; import org.apache.jena.util.CollectionFactory ; import org.apache.jena.util.iterator.ExtendedIterator ; import org.apache.jena.util.iterator.NullIterator ; /** * <p> * A graph implementation that presents the union of zero or more subgraphs, * one of which is distinguished as the updateable graph. * </p> */ public class MultiUnion extends Polyadic { /** * <p> * Construct a union of exactly no sub graphs. * </p> */ public MultiUnion() { super(); } /** * <p> * Construct a union of all of the given graphs * </p> * * @param graphs An array of the sub-graphs of this union */ public MultiUnion( Graph[] graphs) { super( graphs ); } /** * <p> * Construct a union of all of the given graphs. * </p> * * @param graphs An iterator of the sub-graphs of this union. If graphs is * a closable iterator, it will be automatically closed. */ public MultiUnion( Iterator<Graph> graphs ) { super( graphs ); } /** Answer true iff we're optimising find and query over unions with a single element. */ private boolean optimiseOne() { return optimising && m_subGraphs.size() == 1; } private boolean optimising = JenaRuntime.getSystemProperty( "jena.union.optimise", "yes" ).equals( "yes" ); @Override protected GraphStatisticsHandler createStatisticsHandler() { return new MultiUnionStatisticsHandler( this ); } /** * <p> * Add the given triple to the union model; the actual component model to * be updated will be the designated (or default) {@linkplain #getBaseGraph updateable} graph. * </p> * * @param t A triple to add to the union graph * @exception JenaException if the union does not contain any sub-graphs yet */ @Override public void performAdd( Triple t ) { getRequiredBaseGraph().add( t ); } /** * <p> * Delete the given triple from the union model; the actual component model to * be updated will be the designated (or default) {@linkplain #getBaseGraph updateable} graph. * </p> * * @param t A triple to from the union graph * @exception JenaException if the union does not contain any sub-graphs yet */ @Override public void performDelete( Triple t ) { getRequiredBaseGraph().delete( t ); } /** * <p> * Answer true if at least one of the graphs in this union contain the given triple. * </p> * * @param t A triple * @return True if any of the graphs in the union contain t */ @Override public boolean graphBaseContains( Triple t ) { for ( Graph m_subGraph : m_subGraphs ) { if ( m_subGraph.contains( t ) ) { return true; } } return false; } /** * <p> * Answer an iterator over the triples in the union of the graphs in this composition. <b>Note</b> * that the requirement to remove duplicates from the union means that this will be an * expensive operation for large (and especially for persistent) graphs. * </p> * * @param t The matcher to match against * @return An iterator of all triples matching t in the union of the graphs. */ @Override public ExtendedIterator<Triple> graphBaseFind( final Triple t ) { // optimise the case where there's only one component graph. ExtendedIterator<Triple> found = optimiseOne() ? singleGraphFind( t ) : multiGraphFind( t ); return SimpleEventManager.notifyingRemove( MultiUnion.this, found ); } /** Answer the result of <code>find( t )</code> on the single graph in this union. */ private ExtendedIterator<Triple> singleGraphFind( final Triple t ) { return (m_subGraphs.get( 0 )).find( t ); } /** * Answer the concatenation of all the iterators from a-subGraph.find( t ). */ private ExtendedIterator<Triple> multiGraphFind(final Triple t) { Set<Triple> seen = CollectionFactory.createHashedSet() ; ExtendedIterator<Triple> result = NullIterator.instance() ; boolean finished = false ; try { for ( Graph m_subGraph : m_subGraphs ) { ExtendedIterator<Triple> newTriples = recording( rejecting( m_subGraph.find( t ), seen ), seen ); result = result.andThen( newTriples ); } finished = true ; return result ; } finally { // Throwable happened. if (!finished) result.close() ; } } /** * <p> * Add the given graph to this union. If it is already a member of the union, don't * add it a second time. * </p> * * @param graph A sub-graph to add to this union */ @Override public void addGraph( Graph graph ) { if (!m_subGraphs.contains( graph )) { m_subGraphs.add( graph ); } } public static class MultiUnionStatisticsHandler implements GraphStatisticsHandler { protected final MultiUnion mu; public MultiUnionStatisticsHandler( MultiUnion mu ) { this.mu = mu; } @Override public long getStatistic( Node S, Node P, Node O ) { long result = 0; for (int i = 0; i < mu.m_subGraphs.size(); i += 1) { Graph g = mu.m_subGraphs.get( i ); GraphStatisticsHandler s = g.getStatisticsHandler(); long n = s.getStatistic( S, P, O ); if (n < 0) return n; result += n; } return result; } public MultiUnion getUnion() { return mu; } } }