KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgrapht > graph > DefaultListenableGraph


1 /* ==========================================
2  * JGraphT : a free Java graph-theory library
3  * ==========================================
4  *
5  * Project Info: http://jgrapht.sourceforge.net/
6  * Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
7  *
8  * (C) Copyright 2003-2006, by Barak Naveh and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this library; if not, write to the Free Software Foundation,
22  * Inc.,
23  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
24  */

25 /* ---------------------------
26  * DefaultListenableGraph.java
27  * ---------------------------
28  * (C) Copyright 2003-2006, by Barak Naveh and Contributors.
29  *
30  * Original Author: Barak Naveh
31  * Contributor(s): Christian Hammer
32  *
33  * $Id: DefaultListenableGraph.java 504 2006-07-03 02:37:26Z perfecthash $
34  *
35  * Changes
36  * -------
37  * 24-Jul-2003 : Initial revision (BN);
38  * 04-Aug-2003 : Strong refs to listeners instead of weak refs (BN);
39  * 10-Aug-2003 : Adaptation to new event model (BN);
40  * 07-Mar-2004 : Fixed unnecessary clone bug #819075 (BN);
41  * 11-Mar-2004 : Made generic (CH);
42  * 07-May-2006 : Changed from List<Edge> to Set<Edge> (JVS);
43  * 28-May-2006 : Moved connectivity info from edge to graph (JVS);
44  *
45  */

46 package org.jgrapht.graph;
47
48 import java.util.*;
49
50 import org.jgrapht.*;
51 import org.jgrapht.event.*;
52 import org.jgrapht.util.*;
53
54
55 /**
56  * A graph backed by the the graph specified at the constructor, which can be
57  * listened by <code>GraphListener</code> s and by <code>
58  * VertexSetListener</code> s. Operations on this graph "pass through" to the to
59  * the backing graph. Any modification made to this graph or the backing graph
60  * is reflected by the other.
61  *
62  * <p>This graph does <i>not</i> pass the hashCode and equals operations through
63  * to the backing graph, but relies on <tt>Object</tt>'s <tt>equals</tt> and
64  * <tt>hashCode</tt> methods.</p>
65  *
66  * @author Barak Naveh
67  * @see GraphListener
68  * @see VertexSetListener
69  * @since Jul 20, 2003
70  */

71 public class DefaultListenableGraph<V, E>
72     extends GraphDelegator<V, E>
73     implements ListenableGraph<V, E>, Cloneable JavaDoc
74 {
75
76     //~ Static fields/initializers --------------------------------------------
77

78     private static final long serialVersionUID = 3977575900898471984L;
79
80     //~ Instance fields -------------------------------------------------------
81

82     private ArrayList<GraphListener<V, E>> graphListeners =
83         new ArrayList<GraphListener<V, E>>();
84     private ArrayList<VertexSetListener<V>> vertexSetListeners =
85         new ArrayList<VertexSetListener<V>>();
86     private FlyweightEdgeEvent<V, E> reuseableEdgeEvent;
87     private FlyweightVertexEvent<V> reuseableVertexEvent;
88     private boolean reuseEvents;
89
90     //~ Constructors ----------------------------------------------------------
91

92     /**
93      * Creates a new listenable graph.
94      *
95      * @param g the backing graph.
96      */

97     public DefaultListenableGraph(Graph<V, E> g)
98     {
99         this(g, false);
100     }
101
102     /**
103      * Creates a new listenable graph. If the <code>reuseEvents</code> flag is
104      * set to <code>true</code> this class will reuse previously fired events
105      * and will not create a new object for each event. This option increases
106      * performance but should be used with care, especially in multithreaded
107      * environment.
108      *
109      * @param g the backing graph.
110      * @param reuseEvents whether to reuse previously fired event objects
111      * instead of creating a new event object for each event.
112      *
113      * @throws IllegalArgumentException if the backing graph is already a
114      * listenable graph.
115      */

116     public DefaultListenableGraph(Graph<V, E> g, boolean reuseEvents)
117     {
118         super(g);
119         this.reuseEvents = reuseEvents;
120         reuseableEdgeEvent = new FlyweightEdgeEvent<V, E>(this, -1, null);
121         reuseableVertexEvent = new FlyweightVertexEvent<V>(this, -1, null);
122
123         // the following restriction could be probably relaxed in the future.
124
if (g instanceof ListenableGraph) {
125             throw new IllegalArgumentException JavaDoc(
126                 "base graph cannot be listenable");
127         }
128     }
129
130     //~ Methods ---------------------------------------------------------------
131

132     /**
133      * If the <code>reuseEvents</code> flag is set to <code>true</code> this
134      * class will reuse previously fired events and will not create a new object
135      * for each event. This option increases performance but should be used with
136      * care, especially in multithreaded environment.
137      *
138      * @param reuseEvents whether to reuse previously fired event objects
139      * instead of creating a new event object for each event.
140      */

141     public void setReuseEvents(boolean reuseEvents)
142     {
143         this.reuseEvents = reuseEvents;
144     }
145
146     /**
147      * Tests whether the <code>reuseEvents</code> flag is set. If the flag is
148      * set to <code>true</code> this class will reuse previously fired events
149      * and will not create a new object for each event. This option increases
150      * performance but should be used with care, especially in multithreaded
151      * environment.
152      *
153      * @return the value of the <code>reuseEvents</code> flag.
154      */

155     public boolean isReuseEvents()
156     {
157         return reuseEvents;
158     }
159
160     /**
161      * @see Graph#addEdge(Object, Object)
162      */

163     public E addEdge(V sourceVertex, V targetVertex)
164     {
165         E e = super.addEdge(sourceVertex, targetVertex);
166
167         if (e != null) {
168             fireEdgeAdded(e);
169         }
170
171         return e;
172     }
173
174     /**
175      * @see Graph#addEdge(Object, Object, Object)
176      */

177     public boolean addEdge(V sourceVertex, V targetVertex, E e)
178     {
179         boolean added = super.addEdge(sourceVertex, targetVertex, e);
180
181         if (added) {
182             fireEdgeAdded(e);
183         }
184
185         return added;
186     }
187
188     /**
189      * @see ListenableGraph#addGraphListener(GraphListener)
190      */

191     public void addGraphListener(GraphListener<V, E> l)
192     {
193         addToListenerList(graphListeners, l);
194     }
195
196     /**
197      * @see Graph#addVertex(Object)
198      */

199     public boolean addVertex(V v)
200     {
201         boolean modified = super.addVertex(v);
202
203         if (modified) {
204             fireVertexAdded(v);
205         }
206
207         return modified;
208     }
209
210     /**
211      * @see ListenableGraph#addVertexSetListener(VertexSetListener)
212      */

213     public void addVertexSetListener(VertexSetListener<V> l)
214     {
215         addToListenerList(vertexSetListeners, l);
216     }
217
218     /**
219      * @see java.lang.Object#clone()
220      */

221     public Object JavaDoc clone()
222     {
223         try {
224             TypeUtil<DefaultListenableGraph<V, E>> typeDecl = null;
225
226             DefaultListenableGraph<V, E> g =
227                 TypeUtil.uncheckedCast(super.clone(), typeDecl);
228             g.graphListeners = new ArrayList<GraphListener<V, E>>();
229             g.vertexSetListeners = new ArrayList<VertexSetListener<V>>();
230
231             return g;
232         } catch (CloneNotSupportedException JavaDoc e) {
233             // should never get here since we're Cloneable
234
e.printStackTrace();
235             throw new RuntimeException JavaDoc("internal error");
236         }
237     }
238
239     /**
240      * @see Graph#removeEdge(Object, Object)
241      */

242     public E removeEdge(V sourceVertex, V targetVertex)
243     {
244         E e = super.removeEdge(sourceVertex, targetVertex);
245
246         if (e != null) {
247             fireEdgeRemoved(e);
248         }
249
250         return e;
251     }
252
253     /**
254      * @see Graph#removeEdge(Object)
255      */

256     public boolean removeEdge(E e)
257     {
258         boolean modified = super.removeEdge(e);
259
260         if (modified) {
261             fireEdgeRemoved(e);
262         }
263
264         return modified;
265     }
266
267     /**
268      * @see ListenableGraph#removeGraphListener(GraphListener)
269      */

270     public void removeGraphListener(GraphListener<V, E> l)
271     {
272         graphListeners.remove(l);
273     }
274
275     /**
276      * @see Graph#removeVertex(Object)
277      */

278     public boolean removeVertex(V v)
279     {
280         if (containsVertex(v)) {
281             Set<E> touchingEdgesList = edgesOf(v);
282
283             // copy set to avoid ConcurrentModificationException
284
removeAllEdges(new ArrayList<E>(touchingEdgesList));
285
286             super.removeVertex(v); // remove the vertex itself
287

288             fireVertexRemoved(v);
289
290             return true;
291         } else {
292             return false;
293         }
294     }
295
296     /**
297      * @see ListenableGraph#removeVertexSetListener(VertexSetListener)
298      */

299     public void removeVertexSetListener(VertexSetListener<V> l)
300     {
301         vertexSetListeners.remove(l);
302     }
303
304     /**
305      * Notify listeners that the specified edge was added.
306      *
307      * @param edge the edge that was added.
308      */

309     protected void fireEdgeAdded(E edge)
310     {
311         GraphEdgeChangeEvent<V, E> e =
312             createGraphEdgeChangeEvent(GraphEdgeChangeEvent.EDGE_ADDED, edge);
313
314         for (int i = 0; i < graphListeners.size(); i++) {
315             GraphListener<V, E> l = graphListeners.get(i);
316
317             l.edgeAdded(e);
318         }
319     }
320
321     /**
322      * Notify listeners that the specified edge was removed.
323      *
324      * @param edge the edge that was removed.
325      */

326     protected void fireEdgeRemoved(E edge)
327     {
328         GraphEdgeChangeEvent<V, E> e =
329             createGraphEdgeChangeEvent(
330                 GraphEdgeChangeEvent.EDGE_REMOVED,
331                 edge);
332
333         for (int i = 0; i < graphListeners.size(); i++) {
334             GraphListener<V, E> l = graphListeners.get(i);
335
336             l.edgeRemoved(e);
337         }
338     }
339
340     /**
341      * Notify listeners that the specified vertex was added.
342      *
343      * @param vertex the vertex that was added.
344      */

345     protected void fireVertexAdded(V vertex)
346     {
347         GraphVertexChangeEvent<V> e =
348             createGraphVertexChangeEvent(
349                 GraphVertexChangeEvent.VERTEX_ADDED,
350                 vertex);
351
352         for (int i = 0; i < vertexSetListeners.size(); i++) {
353             VertexSetListener<V> l = vertexSetListeners.get(i);
354
355             l.vertexAdded(e);
356         }
357
358         for (int i = 0; i < graphListeners.size(); i++) {
359             GraphListener<V, E> l = graphListeners.get(i);
360
361             l.vertexAdded(e);
362         }
363     }
364
365     /**
366      * Notify listeners that the specified vertex was removed.
367      *
368      * @param vertex the vertex that was removed.
369      */

370     protected void fireVertexRemoved(V vertex)
371     {
372         GraphVertexChangeEvent<V> e =
373             createGraphVertexChangeEvent(
374                 GraphVertexChangeEvent.VERTEX_REMOVED,
375                 vertex);
376
377         for (int i = 0; i < vertexSetListeners.size(); i++) {
378             VertexSetListener<V> l = vertexSetListeners.get(i);
379
380             l.vertexRemoved(e);
381         }
382
383         for (int i = 0; i < graphListeners.size(); i++) {
384             GraphListener<V, E> l = graphListeners.get(i);
385
386             l.vertexRemoved(e);
387         }
388     }
389
390     private static <L extends EventListener> void addToListenerList(
391         List<L> list,
392         L l)
393     {
394         if (!list.contains(l)) {
395             list.add(l);
396         }
397     }
398
399     private GraphEdgeChangeEvent<V, E> createGraphEdgeChangeEvent(
400         int eventType,
401         E edge)
402     {
403         if (reuseEvents) {
404             reuseableEdgeEvent.setType(eventType);
405             reuseableEdgeEvent.setEdge(edge);
406
407             return reuseableEdgeEvent;
408         } else {
409             return new GraphEdgeChangeEvent<V, E>(this, eventType, edge);
410         }
411     }
412
413     private GraphVertexChangeEvent<V> createGraphVertexChangeEvent(
414         int eventType,
415         V vertex)
416     {
417         if (reuseEvents) {
418             reuseableVertexEvent.setType(eventType);
419             reuseableVertexEvent.setVertex(vertex);
420
421             return reuseableVertexEvent;
422         } else {
423             return new GraphVertexChangeEvent<V>(this, eventType, vertex);
424         }
425     }
426
427     //~ Inner Classes ---------------------------------------------------------
428

429     /**
430      * A reuseable edge event.
431      *
432      * @author Barak Naveh
433      * @since Aug 10, 2003
434      */

435     private static class FlyweightEdgeEvent<VV, EE>
436         extends GraphEdgeChangeEvent<VV, EE>
437     {
438         private static final long serialVersionUID = 3907207152526636089L;
439
440         /**
441          * @see GraphEdgeChangeEvent#GraphEdgeChangeEvent(Object, int, Edge)
442          */

443         public FlyweightEdgeEvent(Object JavaDoc eventSource, int type, EE e)
444         {
445             super(eventSource, type, e);
446         }
447
448         /**
449          * Sets the edge of this event.
450          *
451          * @param e the edge to be set.
452          */

453         protected void setEdge(EE e)
454         {
455             this.edge = e;
456         }
457
458         /**
459          * Set the event type of this event.
460          *
461          * @param type the type to be set.
462          */

463         protected void setType(int type)
464         {
465             this.type = type;
466         }
467     }
468
469     /**
470      * A reuseable vertex event.
471      *
472      * @author Barak Naveh
473      * @since Aug 10, 2003
474      */

475     private static class FlyweightVertexEvent<VV>
476         extends GraphVertexChangeEvent<VV>
477     {
478         private static final long serialVersionUID = 3257848787857585716L;
479
480         /**
481          * @see GraphVertexChangeEvent#GraphVertexChangeEvent(Object, int,
482          * Object)
483          */

484         public FlyweightVertexEvent(Object JavaDoc eventSource, int type, VV vertex)
485         {
486             super(eventSource, type, vertex);
487         }
488
489         /**
490          * Set the event type of this event.
491          *
492          * @param type type to be set.
493          */

494         protected void setType(int type)
495         {
496             this.type = type;
497         }
498
499         /**
500          * Sets the vertex of this event.
501          *
502          * @param vertex the vertex to be set.
503          */

504         protected void setVertex(VV vertex)
505         {
506             this.vertex = vertex;
507         }
508     }
509 }
510
Popular Tags