/* * 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 org.apache.jena.graph.impl; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.jena.graph.* ; import org.apache.jena.mem.TrackingTripleIterator ; import org.apache.jena.util.IteratorCollection ; import org.apache.jena.util.iterator.ExtendedIterator ; /** Simple implementation of GraphEventManager for GraphBase to use. The listeners are held as an [Array]List. <p> This class also holds the utility method notifyingRemove, which wraps iterators so that their .remove() operation notifies the specified graph of the removal. */ public class SimpleEventManager implements GraphEventManager { /* Implementation note: * * Use of CopyOnWriteArray is unnecessarily inefficient, in that * a copy is only needed when the register or unregister * is concurrent with an iteration over the list. * Since this list is not public we can either make it private * or provide methods for iterating, so that we know when * it is necessary to copy the array of listeners and when it * isn't. * This is a fair bit of code, and would need either a lock or * an atomic integer or something from the concurrent package. * Until and unless the high cost of registering and unregistering * is an issue I think the current code is elegant and clean. * In practice, most graphs have no more than 10 listeners * so the 10 registrations take 55 word copy operations - nothing * to get upset about. */ /** @deprecated Use the graph passed in in notify operations. */ @Deprecated protected Graph graph; protected List<GraphListener> listeners; /** The graph object for the notification is passed * @deprecated Use the no argument constructor. */ @Deprecated public SimpleEventManager( Graph graph ) { this(); this.graph = graph; } public SimpleEventManager() { this.graph = null ; this.listeners = new CopyOnWriteArrayList<>(); } @Override public GraphEventManager register( GraphListener listener ) { listeners.add( listener ); return this; } @Override public GraphEventManager unregister(GraphListener listener) { listeners.remove(listener) ; return this ; } @Override public boolean listening() { return listeners.size() > 0 ; } @Override public void notifyAddTriple(Graph g, Triple t) { for ( GraphListener l : listeners ) l.notifyAddTriple(g, t) ; } @Override public void notifyAddArray(Graph g, Triple[] ts) { for ( GraphListener l : listeners ) l.notifyAddArray(g, ts) ; } @Override public void notifyAddList(Graph g, List<Triple> L) { for ( GraphListener l : listeners ) l.notifyAddList(g, L) ; } @Override public void notifyAddIterator(Graph g, List<Triple> it) { for ( GraphListener l : listeners ) l.notifyAddIterator(g, it.iterator()) ; } @Override public void notifyAddIterator(Graph g, Iterator<Triple> it) { notifyAddIterator(g, IteratorCollection.iteratorToList(it)) ; } @Override public void notifyAddGraph(Graph g, Graph added) { for ( GraphListener l : listeners ) l.notifyAddGraph(g, added) ; } @Override public void notifyDeleteTriple(Graph g, Triple t) { for ( GraphListener l : listeners ) l.notifyDeleteTriple(g, t) ; } @Override public void notifyDeleteArray(Graph g, Triple[] ts) { for ( GraphListener l : listeners ) l.notifyDeleteArray(g, ts) ; } @Override public void notifyDeleteList(Graph g, List<Triple> L) { for ( GraphListener l : listeners ) l.notifyDeleteList(g, L) ; } @Override public void notifyDeleteIterator(Graph g, List<Triple> L) { for ( GraphListener l : listeners ) l.notifyDeleteIterator(g, L.iterator()) ; } @Override public void notifyDeleteIterator(Graph g, Iterator<Triple> it) { notifyDeleteIterator(g, IteratorCollection.iteratorToList(it)) ; } @Override public void notifyDeleteGraph(Graph g, Graph removed) { for ( GraphListener l : listeners ) l.notifyDeleteGraph(g, removed) ; } @Override public void notifyEvent(Graph source, Object event) { for ( GraphListener l : listeners ) l.notifyEvent(source, event) ; } /** * Answer an iterator which wraps <code>i</code> to ensure that if a * .remove() is executed on it, the graph <code>g</code> will be notified. */ public static ExtendedIterator<Triple> notifyingRemove(final Graph g, Iterator<Triple> i) { return new TrackingTripleIterator(i) { protected final GraphEventManager gem = g.getEventManager() ; @Override public void remove() { super.remove() ; gem.notifyDeleteTriple(g, current) ; } } ; } }