001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.stream; 033 034import java.util.ArrayList; 035import java.util.LinkedList; 036import java.util.List; 037 038import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent; 039import org.graphstream.stream.sync.SourceTime; 040 041/** 042 * Base implementation of an input that provide basic sink handling. 043 * 044 * <p> 045 * This implementation can register a set of graph sinks (or separate sets of 046 * attributes or elements sinks) and provides protected methods to easily 047 * broadcast events to all the sinks (beginning with "send"). 048 * </p> 049 * 050 * <p> 051 * Each time you want to produce an event toward all registered sinks, you call 052 * one of the "send*" methods with correct parameters. The parameters of the 053 * "send*" methods maps to the usual GraphStream events. 054 * </p> 055 * 056 * <p> 057 * This class is "reentrant". This means that if a send*() method is called 058 * during the execution of another or the same send*() method, the event is 059 * deferred until the first send*() method is finished. This avoid recursive 060 * loops if a sink modifies the input during event handling. 061 * </p> 062 */ 063public abstract class SourceBase implements Source { 064 // Attribute 065 066 public enum ElementType { 067 NODE, EDGE, GRAPH 068 }; 069 070 /** 071 * Set of graph attributes sinks. 072 */ 073 protected ArrayList<AttributeSink> attrSinks = new ArrayList<AttributeSink>(); 074 075 /** 076 * Set of graph elements sinks. 077 */ 078 protected ArrayList<ElementSink> eltsSinks = new ArrayList<ElementSink>(); 079 080 /** 081 * A queue that allow the management of events (nodes/edge 082 * add/delete/change) in the right order. 083 */ 084 protected LinkedList<GraphEvent> eventQueue = new LinkedList<GraphEvent>(); 085 086 /** 087 * A boolean that indicates whether or not an Sink event is being sent 088 * during another one. 089 */ 090 protected boolean eventProcessing = false; 091 092 /** 093 * Id of this source. 094 */ 095 protected String sourceId; 096 097 /** 098 * Time of this source. 099 */ 100 protected SourceTime sourceTime; 101 102 // Construction 103 104 protected SourceBase() { 105 this(String.format("sourceOnThread#%d_%d", Thread.currentThread() 106 .getId(), System.currentTimeMillis() 107 + ((int) (Math.random() * 1000)))); 108 } 109 110 protected SourceBase(String sourceId) { 111 this.sourceId = sourceId; 112 this.sourceTime = new SourceTime(sourceId); 113 } 114 115 // Access 116 117 public Iterable<AttributeSink> attributeSinks() { 118 return attrSinks; 119 } 120 121 public Iterable<ElementSink> elementSinks() { 122 return eltsSinks; 123 } 124 125 // Command 126 127 public void addSink(Sink sink) { 128 addAttributeSink(sink); 129 addElementSink(sink); 130 } 131 132 public void addAttributeSink(AttributeSink sink) { 133 if (!eventProcessing) { 134 eventProcessing = true; 135 manageEvents(); 136 137 attrSinks.add(sink); 138 139 manageEvents(); 140 eventProcessing = false; 141 } else { 142 eventQueue.add(new AddToListEvent<AttributeSink>(attrSinks, sink)); 143 } 144 } 145 146 public void addElementSink(ElementSink sink) { 147 if (!eventProcessing) { 148 eventProcessing = true; 149 manageEvents(); 150 151 eltsSinks.add(sink); 152 153 manageEvents(); 154 eventProcessing = false; 155 } else { 156 eventQueue.add(new AddToListEvent<ElementSink>(eltsSinks, sink)); 157 } 158 } 159 160 public void clearSinks() { 161 clearElementSinks(); 162 clearAttributeSinks(); 163 } 164 165 public void clearElementSinks() { 166 if (!eventProcessing) { 167 eventProcessing = true; 168 manageEvents(); 169 170 eltsSinks.clear(); 171 172 manageEvents(); 173 eventProcessing = false; 174 } else { 175 eventQueue.add(new ClearListEvent<ElementSink>(eltsSinks)); 176 } 177 } 178 179 public void clearAttributeSinks() { 180 if (!eventProcessing) { 181 eventProcessing = true; 182 manageEvents(); 183 184 attrSinks.clear(); 185 186 manageEvents(); 187 eventProcessing = false; 188 } else { 189 eventQueue.add(new ClearListEvent<AttributeSink>(attrSinks)); 190 } 191 } 192 193 public void removeSink(Sink sink) { 194 removeAttributeSink(sink); 195 removeElementSink(sink); 196 } 197 198 public void removeAttributeSink(AttributeSink sink) { 199 if (!eventProcessing) { 200 eventProcessing = true; 201 manageEvents(); 202 203 attrSinks.remove(sink); 204 205 manageEvents(); 206 eventProcessing = false; 207 } else { 208 eventQueue.add(new RemoveFromListEvent<AttributeSink>(attrSinks, 209 sink)); 210 } 211 } 212 213 public void removeElementSink(ElementSink sink) { 214 if (!eventProcessing) { 215 eventProcessing = true; 216 manageEvents(); 217 218 eltsSinks.remove(sink); 219 220 manageEvents(); 221 eventProcessing = false; 222 } else { 223 eventQueue 224 .add(new RemoveFromListEvent<ElementSink>(eltsSinks, sink)); 225 } 226 } 227 228 /** 229 * Send a "graph cleared" event to all element sinks. 230 * 231 * @param sourceId 232 * The source identifier. 233 */ 234 public void sendGraphCleared(String sourceId) { 235 sendGraphCleared(sourceId, sourceTime.newEvent()); 236 } 237 238 /** 239 * Send a "graph cleared" event to all element sinks. 240 * 241 * @param sourceId 242 * The source identifier. 243 * @param timeId 244 */ 245 public void sendGraphCleared(String sourceId, long timeId) { 246 if (!eventProcessing) { 247 eventProcessing = true; 248 manageEvents(); 249 250 for (int i = 0; i < eltsSinks.size(); i++) 251 eltsSinks.get(i).graphCleared(sourceId, timeId); 252 253 manageEvents(); 254 eventProcessing = false; 255 } else { 256 eventQueue.add(new BeforeGraphClearEvent(sourceId, timeId)); 257 } 258 } 259 260 /** 261 * Send a "step begins" event to all element sinks. 262 * 263 * @param sourceId 264 * The graph identifier. 265 * @param step 266 * The step time stamp. 267 */ 268 public void sendStepBegins(String sourceId, double step) { 269 sendStepBegins(sourceId, sourceTime.newEvent(), step); 270 } 271 272 /** 273 * Send a "step begins" event to all element sinks. 274 * 275 * @param sourceId 276 * The graph identifier. 277 * @param timeId 278 * @param step 279 * The step time stamp. 280 */ 281 public void sendStepBegins(String sourceId, long timeId, double step) { 282 if (!eventProcessing) { 283 eventProcessing = true; 284 manageEvents(); 285 286 for (int i = 0; i < eltsSinks.size(); i++) 287 eltsSinks.get(i).stepBegins(sourceId, timeId, step); 288 289 manageEvents(); 290 eventProcessing = false; 291 } else { 292 eventQueue.add(new StepBeginsEvent(sourceId, timeId, step)); 293 } 294 } 295 296 /** 297 * Send a "node added" event to all element sinks. 298 * 299 * @param sourceId 300 * The source identifier. 301 * @param nodeId 302 * The node identifier. 303 */ 304 public void sendNodeAdded(String sourceId, String nodeId) { 305 sendNodeAdded(sourceId, sourceTime.newEvent(), nodeId); 306 } 307 308 /** 309 * Send a "node added" event to all element sinks. 310 * 311 * @param sourceId 312 * The source identifier. 313 * @param timeId 314 * @param nodeId 315 * The node identifier. 316 */ 317 public void sendNodeAdded(String sourceId, long timeId, String nodeId) { 318 if (!eventProcessing) { 319 eventProcessing = true; 320 manageEvents(); 321 322 for (int i = 0; i < eltsSinks.size(); i++) 323 eltsSinks.get(i).nodeAdded(sourceId, timeId, nodeId); 324 325 manageEvents(); 326 eventProcessing = false; 327 } else { 328 eventQueue.add(new AfterNodeAddEvent(sourceId, timeId, nodeId)); 329 } 330 } 331 332 /** 333 * Send a "node removed" event to all element sinks. 334 * 335 * @param sourceId 336 * The graph identifier. 337 * @param nodeId 338 * The node identifier. 339 */ 340 public void sendNodeRemoved(String sourceId, String nodeId) { 341 sendNodeRemoved(sourceId, sourceTime.newEvent(), nodeId); 342 } 343 344 /** 345 * Send a "node removed" event to all element sinks. 346 * 347 * @param sourceId 348 * The graph identifier. 349 * @param timeId 350 * @param nodeId 351 * The node identifier. 352 */ 353 public void sendNodeRemoved(String sourceId, long timeId, String nodeId) { 354 if (!eventProcessing) { 355 eventProcessing = true; 356 manageEvents(); 357 358 for (int i = 0; i < eltsSinks.size(); i++) 359 eltsSinks.get(i).nodeRemoved(sourceId, timeId, nodeId); 360 361 manageEvents(); 362 eventProcessing = false; 363 } else { 364 eventQueue.add(new BeforeNodeRemoveEvent(sourceId, timeId, nodeId)); 365 } 366 } 367 368 /** 369 * Send an "edge added" event to all element sinks. 370 * 371 * @param sourceId 372 * The source identifier. 373 * @param edgeId 374 * The edge identifier. 375 * @param fromNodeId 376 * The edge start node. 377 * @param toNodeId 378 * The edge end node. 379 * @param directed 380 * Is the edge directed?. 381 */ 382 public void sendEdgeAdded(String sourceId, String edgeId, 383 String fromNodeId, String toNodeId, boolean directed) { 384 sendEdgeAdded(sourceId, sourceTime.newEvent(), edgeId, fromNodeId, 385 toNodeId, directed); 386 } 387 388 /** 389 * Send an "edge added" event to all element sinks. 390 * 391 * @param sourceId 392 * The source identifier. 393 * @param timeId 394 * @param edgeId 395 * The edge identifier. 396 * @param fromNodeId 397 * The edge start node. 398 * @param toNodeId 399 * The edge end node. 400 * @param directed 401 * Is the edge directed?. 402 */ 403 public void sendEdgeAdded(String sourceId, long timeId, String edgeId, 404 String fromNodeId, String toNodeId, boolean directed) { 405 if (!eventProcessing) { 406 eventProcessing = true; 407 manageEvents(); 408 409 for (int i = 0; i < eltsSinks.size(); i++) 410 eltsSinks.get(i).edgeAdded(sourceId, timeId, edgeId, 411 fromNodeId, toNodeId, directed); 412 413 manageEvents(); 414 eventProcessing = false; 415 } else { 416 eventQueue.add(new AfterEdgeAddEvent(sourceId, timeId, edgeId, 417 fromNodeId, toNodeId, directed)); 418 } 419 } 420 421 /** 422 * Send a "edge removed" event to all element sinks. 423 * 424 * @param sourceId 425 * The source identifier. 426 * @param edgeId 427 * The edge identifier. 428 */ 429 public void sendEdgeRemoved(String sourceId, String edgeId) { 430 sendEdgeRemoved(sourceId, sourceTime.newEvent(), edgeId); 431 } 432 433 /** 434 * Send a "edge removed" event to all element sinks. 435 * 436 * @param sourceId 437 * The source identifier. 438 * @param timeId 439 * @param edgeId 440 * The edge identifier. 441 */ 442 public void sendEdgeRemoved(String sourceId, long timeId, String edgeId) { 443 if (!eventProcessing) { 444 eventProcessing = true; 445 manageEvents(); 446 447 for (int i = 0; i < eltsSinks.size(); i++) 448 eltsSinks.get(i).edgeRemoved(sourceId, timeId, edgeId); 449 450 manageEvents(); 451 eventProcessing = false; 452 } else { 453 eventQueue.add(new BeforeEdgeRemoveEvent(sourceId, timeId, edgeId)); 454 } 455 } 456 457 /** 458 * Send a "edge attribute added" event to all attribute sinks. 459 * 460 * @param sourceId 461 * The source identifier. 462 * @param edgeId 463 * The edge identifier. 464 * @param attribute 465 * The attribute name. 466 * @param value 467 * The attribute value. 468 */ 469 public void sendEdgeAttributeAdded(String sourceId, String edgeId, 470 String attribute, Object value) { 471 sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE, 472 attribute, AttributeChangeEvent.ADD, null, value); 473 } 474 475 /** 476 * Send a "edge attribute added" event to all attribute sinks. 477 * 478 * @param sourceId 479 * The source identifier. 480 * @param timeId 481 * @param edgeId 482 * The edge identifier. 483 * @param attribute 484 * The attribute name. 485 * @param value 486 * The attribute value. 487 */ 488 public void sendEdgeAttributeAdded(String sourceId, long timeId, 489 String edgeId, String attribute, Object value) { 490 sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE, 491 attribute, AttributeChangeEvent.ADD, null, value); 492 } 493 494 /** 495 * Send a "edge attribute changed" event to all attribute sinks. 496 * 497 * @param sourceId 498 * The source identifier. 499 * @param edgeId 500 * The edge identifier. 501 * @param attribute 502 * The attribute name. 503 * @param oldValue 504 * The old attribute value. 505 * @param newValue 506 * The new attribute value. 507 */ 508 public void sendEdgeAttributeChanged(String sourceId, String edgeId, 509 String attribute, Object oldValue, Object newValue) { 510 sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE, 511 attribute, AttributeChangeEvent.CHANGE, oldValue, newValue); 512 } 513 514 /** 515 * Send a "edge attribute changed" event to all attribute sinks. 516 * 517 * @param sourceId 518 * The source identifier. 519 * @param timeId 520 * @param edgeId 521 * The edge identifier. 522 * @param attribute 523 * The attribute name. 524 * @param oldValue 525 * The old attribute value. 526 * @param newValue 527 * The new attribute value. 528 */ 529 public void sendEdgeAttributeChanged(String sourceId, long timeId, 530 String edgeId, String attribute, Object oldValue, Object newValue) { 531 sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE, 532 attribute, AttributeChangeEvent.CHANGE, oldValue, newValue); 533 } 534 535 /** 536 * Send a "edge attribute removed" event to all attribute sinks. 537 * 538 * @param sourceId 539 * The source identifier. 540 * @param edgeId 541 * The edge identifier. 542 * @param attribute 543 * The attribute name. 544 */ 545 public void sendEdgeAttributeRemoved(String sourceId, String edgeId, 546 String attribute) { 547 sendAttributeChangedEvent(sourceId, edgeId, ElementType.EDGE, 548 attribute, AttributeChangeEvent.REMOVE, null, null); 549 } 550 551 /** 552 * Send a "edge attribute removed" event to all attribute sinks. 553 * 554 * @param sourceId 555 * The source identifier. 556 * @param timeId 557 * @param edgeId 558 * The edge identifier. 559 * @param attribute 560 * The attribute name. 561 */ 562 public void sendEdgeAttributeRemoved(String sourceId, long timeId, 563 String edgeId, String attribute) { 564 sendAttributeChangedEvent(sourceId, timeId, edgeId, ElementType.EDGE, 565 attribute, AttributeChangeEvent.REMOVE, null, null); 566 } 567 568 /** 569 * Send a "graph attribute added" event to all attribute sinks. 570 * 571 * @param sourceId 572 * The source identifier. 573 * @param attribute 574 * The attribute name. 575 * @param value 576 * The attribute value. 577 */ 578 public void sendGraphAttributeAdded(String sourceId, String attribute, 579 Object value) { 580 sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute, 581 AttributeChangeEvent.ADD, null, value); 582 } 583 584 /** 585 * Send a "graph attribute added" event to all attribute sinks. 586 * 587 * @param sourceId 588 * The source identifier. 589 * @param timeId 590 * @param attribute 591 * The attribute name. 592 * @param value 593 * The attribute value. 594 */ 595 public void sendGraphAttributeAdded(String sourceId, long timeId, 596 String attribute, Object value) { 597 sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH, 598 attribute, AttributeChangeEvent.ADD, null, value); 599 } 600 601 /** 602 * Send a "graph attribute changed" event to all attribute sinks. 603 * 604 * @param sourceId 605 * The source identifier. 606 * @param attribute 607 * The attribute name. 608 * @param oldValue 609 * The attribute old value. 610 * @param newValue 611 * The attribute new value. 612 */ 613 public void sendGraphAttributeChanged(String sourceId, String attribute, 614 Object oldValue, Object newValue) { 615 sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute, 616 AttributeChangeEvent.CHANGE, oldValue, newValue); 617 } 618 619 /** 620 * Send a "graph attribute changed" event to all attribute sinks. 621 * 622 * @param sourceId 623 * The source identifier. 624 * @param timeId 625 * @param attribute 626 * The attribute name. 627 * @param oldValue 628 * The attribute old value. 629 * @param newValue 630 * The attribute new value. 631 */ 632 public void sendGraphAttributeChanged(String sourceId, long timeId, 633 String attribute, Object oldValue, Object newValue) { 634 sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH, 635 attribute, AttributeChangeEvent.CHANGE, oldValue, newValue); 636 } 637 638 /** 639 * Send a "graph attribute removed" event to all attribute sinks. 640 * 641 * @param sourceId 642 * The source identifier. 643 * @param attribute 644 * The attribute name. 645 */ 646 public void sendGraphAttributeRemoved(String sourceId, String attribute) { 647 sendAttributeChangedEvent(sourceId, null, ElementType.GRAPH, attribute, 648 AttributeChangeEvent.REMOVE, null, null); 649 } 650 651 /** 652 * Send a "graph attribute removed" event to all attribute sinks. 653 * 654 * @param sourceId 655 * The source identifier. 656 * @param timeId 657 * @param attribute 658 * The attribute name. 659 */ 660 public void sendGraphAttributeRemoved(String sourceId, long timeId, 661 String attribute) { 662 sendAttributeChangedEvent(sourceId, timeId, null, ElementType.GRAPH, 663 attribute, AttributeChangeEvent.REMOVE, null, null); 664 } 665 666 /** 667 * Send a "node attribute added" event to all attribute sinks. 668 * 669 * @param sourceId 670 * The source identifier. 671 * @param nodeId 672 * The node identifier. 673 * @param attribute 674 * The attribute name. 675 * @param value 676 * The attribute value. 677 */ 678 public void sendNodeAttributeAdded(String sourceId, String nodeId, 679 String attribute, Object value) { 680 sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE, 681 attribute, AttributeChangeEvent.ADD, null, value); 682 } 683 684 /** 685 * Send a "node attribute added" event to all attribute sinks. 686 * 687 * @param sourceId 688 * The source identifier. 689 * @param timeId 690 * @param nodeId 691 * The node identifier. 692 * @param attribute 693 * The attribute name. 694 * @param value 695 * The attribute value. 696 */ 697 public void sendNodeAttributeAdded(String sourceId, long timeId, 698 String nodeId, String attribute, Object value) { 699 sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE, 700 attribute, AttributeChangeEvent.ADD, null, value); 701 } 702 703 /** 704 * Send a "node attribute changed" event to all attribute sinks. 705 * 706 * @param sourceId 707 * The source identifier. 708 * @param nodeId 709 * The node identifier. 710 * @param attribute 711 * The attribute name. 712 * @param oldValue 713 * The attribute old value. 714 * @param newValue 715 * The attribute new value. 716 */ 717 public void sendNodeAttributeChanged(String sourceId, String nodeId, 718 String attribute, Object oldValue, Object newValue) { 719 sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE, 720 attribute, AttributeChangeEvent.CHANGE, oldValue, newValue); 721 } 722 723 /** 724 * Send a "node attribute changed" event to all attribute sinks. 725 * 726 * @param sourceId 727 * The source identifier. 728 * @param timeId 729 * @param nodeId 730 * The node identifier. 731 * @param attribute 732 * The attribute name. 733 * @param oldValue 734 * The attribute old value. 735 * @param newValue 736 * The attribute new value. 737 */ 738 public void sendNodeAttributeChanged(String sourceId, long timeId, 739 String nodeId, String attribute, Object oldValue, Object newValue) { 740 sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE, 741 attribute, AttributeChangeEvent.CHANGE, oldValue, newValue); 742 } 743 744 /** 745 * Send a "node attribute removed" event to all attribute sinks. 746 * 747 * @param sourceId 748 * The source identifier. 749 * @param nodeId 750 * The node identifier. 751 * @param attribute 752 * The attribute name. 753 */ 754 public void sendNodeAttributeRemoved(String sourceId, String nodeId, 755 String attribute) { 756 sendAttributeChangedEvent(sourceId, nodeId, ElementType.NODE, 757 attribute, AttributeChangeEvent.REMOVE, null, null); 758 } 759 760 /** 761 * Send a "node attribute removed" event to all attribute sinks. 762 * 763 * @param sourceId 764 * The source identifier. 765 * @param timeId 766 * @param nodeId 767 * The node identifier. 768 * @param attribute 769 * The attribute name. 770 */ 771 public void sendNodeAttributeRemoved(String sourceId, long timeId, 772 String nodeId, String attribute) { 773 sendAttributeChangedEvent(sourceId, timeId, nodeId, ElementType.NODE, 774 attribute, AttributeChangeEvent.REMOVE, null, null); 775 } 776 777 /** 778 * Send a add/change/remove attribute event on an element. This method is a 779 * generic way of notifying of an attribute change and is equivalent to 780 * individual send*Attribute*() methods. 781 * 782 * @param sourceId 783 * The source identifier. 784 * @param eltId 785 * The changed element identifier. 786 * @param eltType 787 * The changed element type. 788 * @param attribute 789 * The changed attribute. 790 * @param event 791 * The add/change/remove action. 792 * @param oldValue 793 * The old attribute value (null if the attribute is removed or 794 * added). 795 * @param newValue 796 * The new attribute value (null if removed). 797 */ 798 public void sendAttributeChangedEvent(String sourceId, String eltId, 799 ElementType eltType, String attribute, AttributeChangeEvent event, 800 Object oldValue, Object newValue) { 801 sendAttributeChangedEvent(sourceId, sourceTime.newEvent(), eltId, 802 eltType, attribute, event, oldValue, newValue); 803 } 804 805 public void sendAttributeChangedEvent(String sourceId, long timeId, 806 String eltId, ElementType eltType, String attribute, 807 AttributeChangeEvent event, Object oldValue, Object newValue) { 808 if (!eventProcessing) { 809 eventProcessing = true; 810 manageEvents(); 811 812 if (event == AttributeChangeEvent.ADD) { 813 if (eltType == ElementType.NODE) { 814 for (int i = 0; i < attrSinks.size(); i++) 815 attrSinks.get(i).nodeAttributeAdded(sourceId, timeId, 816 eltId, attribute, newValue); 817 } else if (eltType == ElementType.EDGE) { 818 for (int i = 0; i < attrSinks.size(); i++) 819 attrSinks.get(i).edgeAttributeAdded(sourceId, timeId, 820 eltId, attribute, newValue); 821 } else { 822 for (int i = 0; i < attrSinks.size(); i++) 823 attrSinks.get(i).graphAttributeAdded(sourceId, timeId, 824 attribute, newValue); 825 } 826 } else if (event == AttributeChangeEvent.REMOVE) { 827 if (eltType == ElementType.NODE) { 828 for (int i = 0; i < attrSinks.size(); i++) 829 attrSinks.get(i).nodeAttributeRemoved(sourceId, timeId, 830 eltId, attribute); 831 } else if (eltType == ElementType.EDGE) { 832 for (int i = 0; i < attrSinks.size(); i++) 833 attrSinks.get(i).edgeAttributeRemoved(sourceId, timeId, 834 eltId, attribute); 835 } else { 836 for (int i = 0; i < attrSinks.size(); i++) 837 attrSinks.get(i).graphAttributeRemoved(sourceId, 838 timeId, attribute); 839 } 840 } else { 841 if (eltType == ElementType.NODE) { 842 for (int i = 0; i < attrSinks.size(); i++) 843 attrSinks.get(i).nodeAttributeChanged(sourceId, timeId, 844 eltId, attribute, oldValue, newValue); 845 } else if (eltType == ElementType.EDGE) { 846 for (int i = 0; i < attrSinks.size(); i++) 847 attrSinks.get(i).edgeAttributeChanged(sourceId, timeId, 848 eltId, attribute, oldValue, newValue); 849 } else { 850 for (int i = 0; i < attrSinks.size(); i++) 851 attrSinks.get(i).graphAttributeChanged(sourceId, 852 timeId, attribute, oldValue, newValue); 853 } 854 } 855 856 manageEvents(); 857 eventProcessing = false; 858 } else { 859 eventQueue.add(new AttributeChangedEvent(sourceId, timeId, eltId, 860 eltType, attribute, event, oldValue, newValue)); 861 } 862 } 863 864 // Deferred event management 865 866 /** 867 * If in "event processing mode", ensure all pending events are processed. 868 */ 869 protected void manageEvents() { 870 if (eventProcessing) { 871 while (!eventQueue.isEmpty()) 872 eventQueue.remove().trigger(); 873 } 874 } 875 876 // Events Management 877 878 /** 879 * Interface that provide general purpose classification for evens involved 880 * in graph modifications 881 */ 882 abstract class GraphEvent { 883 String sourceId; 884 long timeId; 885 886 GraphEvent(String sourceId, long timeId) { 887 this.sourceId = sourceId; 888 this.timeId = timeId; 889 } 890 891 abstract void trigger(); 892 } 893 894 class AfterEdgeAddEvent extends GraphEvent { 895 String edgeId; 896 String fromNodeId; 897 String toNodeId; 898 boolean directed; 899 900 AfterEdgeAddEvent(String sourceId, long timeId, String edgeId, 901 String fromNodeId, String toNodeId, boolean directed) { 902 super(sourceId, timeId); 903 this.edgeId = edgeId; 904 this.fromNodeId = fromNodeId; 905 this.toNodeId = toNodeId; 906 this.directed = directed; 907 } 908 909 void trigger() { 910 for (int i = 0; i < eltsSinks.size(); i++) 911 eltsSinks.get(i).edgeAdded(sourceId, timeId, edgeId, 912 fromNodeId, toNodeId, directed); 913 } 914 } 915 916 class BeforeEdgeRemoveEvent extends GraphEvent { 917 String edgeId; 918 919 BeforeEdgeRemoveEvent(String sourceId, long timeId, String edgeId) { 920 super(sourceId, timeId); 921 this.edgeId = edgeId; 922 } 923 924 void trigger() { 925 for (int i = 0; i < eltsSinks.size(); i++) 926 eltsSinks.get(i).edgeRemoved(sourceId, timeId, edgeId); 927 } 928 } 929 930 class AfterNodeAddEvent extends GraphEvent { 931 String nodeId; 932 933 AfterNodeAddEvent(String sourceId, long timeId, String nodeId) { 934 super(sourceId, timeId); 935 this.nodeId = nodeId; 936 } 937 938 void trigger() { 939 for (int i = 0; i < eltsSinks.size(); i++) 940 eltsSinks.get(i).nodeAdded(sourceId, timeId, nodeId); 941 } 942 } 943 944 class BeforeNodeRemoveEvent extends GraphEvent { 945 String nodeId; 946 947 BeforeNodeRemoveEvent(String sourceId, long timeId, String nodeId) { 948 super(sourceId, timeId); 949 this.nodeId = nodeId; 950 } 951 952 void trigger() { 953 for (int i = 0; i < eltsSinks.size(); i++) 954 eltsSinks.get(i).nodeRemoved(sourceId, timeId, nodeId); 955 } 956 } 957 958 class BeforeGraphClearEvent extends GraphEvent { 959 BeforeGraphClearEvent(String sourceId, long timeId) { 960 super(sourceId, timeId); 961 } 962 963 void trigger() { 964 for (int i = 0; i < eltsSinks.size(); i++) 965 eltsSinks.get(i).graphCleared(sourceId, timeId); 966 } 967 } 968 969 class StepBeginsEvent extends GraphEvent { 970 double step; 971 972 StepBeginsEvent(String sourceId, long timeId, double step) { 973 super(sourceId, timeId); 974 this.step = step; 975 } 976 977 void trigger() { 978 for (int i = 0; i < eltsSinks.size(); i++) 979 eltsSinks.get(i).stepBegins(sourceId, timeId, step); 980 } 981 } 982 983 class AttributeChangedEvent extends GraphEvent { 984 ElementType eltType; 985 986 String eltId; 987 988 String attribute; 989 990 AttributeChangeEvent event; 991 992 Object oldValue; 993 994 Object newValue; 995 996 AttributeChangedEvent(String sourceId, long timeId, String eltId, 997 ElementType eltType, String attribute, 998 AttributeChangeEvent event, Object oldValue, Object newValue) { 999 super(sourceId, timeId); 1000 this.eltType = eltType; 1001 this.eltId = eltId; 1002 this.attribute = attribute; 1003 this.event = event; 1004 this.oldValue = oldValue; 1005 this.newValue = newValue; 1006 } 1007 1008 void trigger() { 1009 switch (event) { 1010 case ADD: 1011 switch (eltType) { 1012 case NODE: 1013 for (int i = 0; i < attrSinks.size(); i++) 1014 attrSinks.get(i).nodeAttributeAdded(sourceId, timeId, 1015 eltId, attribute, newValue); 1016 break; 1017 case EDGE: 1018 for (int i = 0; i < attrSinks.size(); i++) 1019 attrSinks.get(i).edgeAttributeAdded(sourceId, timeId, 1020 eltId, attribute, newValue); 1021 break; 1022 default: 1023 for (int i = 0; i < attrSinks.size(); i++) 1024 attrSinks.get(i).graphAttributeAdded(sourceId, timeId, 1025 attribute, newValue); 1026 } 1027 break; 1028 case REMOVE: 1029 switch (eltType) { 1030 case NODE: 1031 for (int i = 0; i < attrSinks.size(); i++) 1032 attrSinks.get(i).nodeAttributeRemoved(sourceId, timeId, 1033 eltId, attribute); 1034 break; 1035 case EDGE: 1036 for (int i = 0; i < attrSinks.size(); i++) 1037 attrSinks.get(i).edgeAttributeRemoved(sourceId, timeId, 1038 eltId, attribute); 1039 break; 1040 default: 1041 for (int i = 0; i < attrSinks.size(); i++) 1042 attrSinks.get(i).graphAttributeRemoved(sourceId, 1043 timeId, attribute); 1044 } 1045 break; 1046 default: 1047 switch (eltType) { 1048 case NODE: 1049 for (int i = 0; i < attrSinks.size(); i++) 1050 attrSinks.get(i).nodeAttributeChanged(sourceId, timeId, 1051 eltId, attribute, oldValue, newValue); 1052 break; 1053 case EDGE: 1054 for (int i = 0; i < attrSinks.size(); i++) 1055 attrSinks.get(i).edgeAttributeChanged(sourceId, timeId, 1056 eltId, attribute, oldValue, newValue); 1057 break; 1058 default: 1059 for (int i = 0; i < attrSinks.size(); i++) 1060 attrSinks.get(i).graphAttributeChanged(sourceId, 1061 timeId, attribute, oldValue, newValue); 1062 } 1063 } 1064 } 1065 } 1066 1067 class AddToListEvent<T> extends GraphEvent { 1068 List<T> l; 1069 T obj; 1070 1071 AddToListEvent(List<T> l, T obj) { 1072 super(null, -1); 1073 this.l = l; 1074 this.obj = obj; 1075 } 1076 1077 void trigger() { 1078 l.add(obj); 1079 } 1080 } 1081 1082 class RemoveFromListEvent<T> extends GraphEvent { 1083 List<T> l; 1084 T obj; 1085 1086 RemoveFromListEvent(List<T> l, T obj) { 1087 super(null, -1); 1088 this.l = l; 1089 this.obj = obj; 1090 } 1091 1092 void trigger() { 1093 l.remove(obj); 1094 } 1095 } 1096 1097 class ClearListEvent<T> extends GraphEvent { 1098 List<T> l; 1099 1100 ClearListEvent(List<T> l) { 1101 super(null, -1); 1102 this.l = l; 1103 } 1104 1105 void trigger() { 1106 l.clear(); 1107 } 1108 } 1109}