001 package data.filters; 002 003 import data.*; 004 import data.events.*; 005 006 import util.*; 007 008 import java.util.*; 009 import java.beans.*; 010 import java.io.*; 011 012 /** 013 * <i>Abstract</i> superclass of all Stock filters. By using a Stock filter you can present partial views of 014 * a Stock to certain parts of your application, e.g., to the GUI elements. However, you cannot use this Stock 015 * as a replacement for a 'real' Stock, e.g., as an item in another Stock. 016 * 017 * <p>The concrete filter condition is implemented by subclassing either {@link CountingStockFilter} or 018 * {@link StoringStockFilter} and overriding some method. The concrete semantics is documented with the 019 * concrete subclass of AbstractStockFilter.</p> 020 * 021 * @author Steffen Zschaler 022 * @version 2.0 19/08/1999 023 * @since v2.0 024 */ 025 public abstract class AbstractStockFilter<T extends StockItem, CT extends CatalogItem> 026 extends Object implements ListenableStock<T, CT>, StockChangeListener<T, CT> { 027 028 /** 029 * The Stock that gets filtered. 030 * 031 * @serial 032 */ 033 protected Stock<T, CT> m_stSource; 034 035 /** 036 * The list of listeners of this Stock. 037 * 038 * @serial 039 */ 040 protected ListenerHelper m_lhListeners = new ListenerHelper(); 041 042 /** 043 * After reading the default serializable fields of the class, re-establish the listener link to our 044 * source. 045 * 046 * @override Never 047 */ 048 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 049 ois.defaultReadObject(); 050 051 if (m_stSource instanceof ListenableStock) { 052 ((ListenableStock<T, CT>)m_stSource).addStockChangeListener(this); 053 } 054 } 055 056 /** 057 * Create a new AbstractStockFilter. May only be called by subclasses. 058 * 059 * @param stSource the Stock to be filtered. 060 */ 061 protected AbstractStockFilter(Stock<T, CT> stSource) { 062 super(); 063 064 m_stSource = stSource; 065 066 if (stSource instanceof ListenableStock) { 067 ((ListenableStock<T, CT>)stSource).addStockChangeListener(this); 068 } 069 } 070 071 /** 072 * Add the given item to the source Stock. 073 * 074 * @override Never 075 */ 076 public void add(T si, DataBasket db) { 077 m_stSource.add(si, db); 078 } 079 080 /** 081 * Add the given Stock to the source Stock. 082 * 083 * @override Never 084 */ 085 public void addStock(Stock<T, CT> st, DataBasket db, boolean fRemove) { 086 m_stSource.addStock(st, db, fRemove); 087 } 088 089 /** 090 * Returns <code>(countItems (sKey, db) >= 0)</code>. 091 * 092 * @override Sometimes 093 */ 094 public boolean contains(String sKey, DataBasket db) { 095 return (countItems(sKey, db) >= 0); 096 } 097 098 /** 099 * Remove the given item from the source Stock. 100 * 101 * @override Never 102 */ 103 public StockItem remove(String sKey, DataBasket db) throws VetoException { 104 if (contains(sKey, db)) { 105 return m_stSource.remove(sKey, db); 106 } else { 107 return null; 108 } 109 } 110 111 /** 112 * Remove the given item from the source Stock. 113 * 114 * @override Never 115 */ 116 public StockItem remove(T si, DataBasket db) throws VetoException { 117 if (contains(si, db)) { 118 return m_stSource.remove(si, db); 119 } else { 120 return null; 121 } 122 } 123 124 /** 125 * Create an iterator that will return all items that match the condition. 126 * 127 * @override Never 128 */ 129 public Iterator<T> iterator(final DataBasket db, final boolean fForEdit) { 130 class I implements Iterator<T> { 131 private Iterator<String> m_iKeys; 132 private Iterator<T> m_iItems; 133 134 public I() { 135 super(); 136 137 m_iKeys = keySet(db).iterator(); 138 } 139 140 public boolean hasNext() { 141 return findNext(); 142 } 143 144 public T next() { 145 if (!findNext()) { 146 throw new NoSuchElementException("No more elements in Stock."); 147 } 148 149 return m_iItems.next(); 150 } 151 152 public void remove() { 153 if (m_iItems == null) { 154 throw new IllegalStateException(); 155 } 156 157 m_iItems.remove(); 158 } 159 160 private boolean findNext() { 161 if (m_iItems == null) { 162 if (m_iKeys.hasNext()) { 163 m_iItems = get((String)m_iKeys.next(), db, fForEdit); 164 } else { 165 return false; 166 } 167 } 168 169 while ((m_iItems.hasNext()) || (m_iKeys.hasNext())) { 170 if (m_iItems.hasNext()) { 171 return true; 172 } 173 174 m_iItems = get((String)m_iKeys.next(), db, fForEdit); 175 } 176 177 return false; 178 } 179 } 180 181 return new I(); 182 } 183 184 /** 185 * Get a filtered key set. 186 * 187 * @override Never 188 */ 189 public Set<String> keySet(DataBasket db) { 190 Set<String> stKeys = m_stSource.keySet(db); 191 192 for (Iterator<String> i = stKeys.iterator(); i.hasNext(); ) { 193 String sKey = i.next(); 194 195 if (!contains(sKey, db)) { 196 stKeys.remove(sKey); 197 } 198 } 199 200 return stKeys; 201 } 202 203 /** 204 * Calculate the total value of the Stock, evaluating only items that match the condition. 205 * 206 * @override Never 207 */ 208 public Value sumStock(DataBasket db, CatalogItemValue civ, Value vInit) { 209 Set<String> stKeys = keySet(db); 210 211 for (Iterator<String> i = stKeys.iterator(); i.hasNext(); ) { 212 String sKey = i.next(); 213 214 try { 215 vInit.addAccumulating(civ.getValue(getCatalog(db).get(sKey, db, 216 false)).multiply(countItems(sKey, db))); 217 } 218 catch (VetoException ex) {} 219 } 220 221 return vInit; 222 } 223 224 /** 225 * Fill the source Stock. 226 * 227 * @override Never 228 */ 229 public Value fillStockWithValue(DataBasket db, Value vTarget, StockFromValueCreator sfvc) { 230 return m_stSource.fillStockWithValue(db, vTarget, sfvc); 231 } 232 233 /** 234 * Calculate the size of the source Stock, considering only items that match the condition. 235 * 236 * @override Never 237 */ 238 public int size(DataBasket db) { 239 Set<String> stKeys = keySet(db); 240 int nSize = 0; 241 242 for (Iterator<String> i = stKeys.iterator(); i.hasNext(); ) { 243 nSize += countItems(i.next(), db); 244 } 245 246 return nSize; 247 } 248 249 /** 250 * Get the source Stock's Catalog. 251 * 252 * @override Never 253 */ 254 public Catalog getCatalog(DataBasket db) { 255 return m_stSource.getCatalog(db); 256 } 257 258 // StockItem interface methods 259 260 /** 261 * Get the source Stock's Stock. 262 * 263 * @override Never 264 */ 265 public Stock getStock() { 266 return m_stSource.getStock(); 267 } 268 269 /** 270 * Get the source stock. If the source stock is a StockFilter again, 271 * return this Stock's MainStock. 272 * 273 * @override Never 274 */ 275 public Stock getMainStock() { 276 if (m_stSource instanceof AbstractStockFilter) { 277 return ((AbstractStockFilter)m_stSource).getMainStock(); 278 } 279 280 return m_stSource; 281 } 282 283 /** 284 * Get the source Stock's associated item. 285 * 286 * @override Never 287 */ 288 public CatalogItem getAssociatedItem(DataBasket db) { 289 return m_stSource.getAssociatedItem(db); 290 } 291 292 // Nameable interface methods 293 /** 294 * Attach the NameContext to the source Stock. 295 * 296 * @override Never 297 */ 298 public NameContext attach(NameContext nc) { 299 return m_stSource.attach(nc); 300 } 301 302 /** 303 * Detach the current NameContext from the source Stock. 304 * 305 * @override Never 306 */ 307 public NameContext detachNC() { 308 return m_stSource.detachNC(); 309 } 310 311 /** 312 * Set the source Stock's name. 313 * 314 * @override Never 315 */ 316 public void setName(String sName, DataBasket db) throws NameContextException { 317 m_stSource.setName(sName, db); 318 } 319 320 /** 321 * Get the source Stock's name. 322 * 323 * @override Never 324 */ 325 public String getName() { 326 return m_stSource.getName(); 327 } 328 329 /** 330 * Register the listener with the source Stock. 331 * 332 * @override Never 333 */ 334 public void addPropertyChangeListener(PropertyChangeListener pcl) { 335 m_stSource.addPropertyChangeListener(pcl); 336 } 337 338 /** 339 * Un-Register the listener with the source Stock. 340 * 341 * @override Never 342 */ 343 public void removePropertyChangeListener(PropertyChangeListener pcl) { 344 m_stSource.removePropertyChangeListener(pcl); 345 } 346 347 /** 348 * Register the listener with the source Stock. 349 * 350 * @override Never 351 */ 352 public void addNameListener(PropertyChangeListener pcl) { 353 m_stSource.addNameListener(pcl); 354 } 355 356 /** 357 * Un-Register the listener with the source Stock. 358 * 359 * @override Never 360 */ 361 public void removeNameListener(PropertyChangeListener pcl) { 362 m_stSource.removeNameListener(pcl); 363 } 364 365 /** 366 * Compare the source Stock to the object. 367 * 368 * @override Never 369 */ 370 public int compareTo(Object o) { 371 return m_stSource.compareTo(o); 372 } 373 374 /** 375 * @override Always 376 */ 377 public abstract Object clone(); 378 379 // ListenableStock interface methods 380 /** 381 * Register a listener that will receive events when the Stock's contents change. 382 * 383 * @override Never 384 */ 385 public void addStockChangeListener(StockChangeListener scl) { 386 m_lhListeners.add(StockChangeListener.class, scl); 387 } 388 389 /** 390 * Un-Register a listener that received events when the Stock's contents changed. 391 * 392 * @override Never 393 */ 394 public void removeStockChangeListener(StockChangeListener scl) { 395 m_lhListeners.remove(StockChangeListener.class, scl); 396 } 397 398 // StockChangeListener interface methods 399 400 /** 401 * Receive the event from the source Stock, translate and propagate it to any listeners. 402 * 403 * @override Never 404 */ 405 public void addedStockItems(StockChangeEvent<T, CT> e) { 406 Set<T> stItems = new HashSet<T>(); 407 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 408 T si = i.next(); 409 410 if (contains(si, e.getBasket())) { 411 stItems.add(si); 412 } 413 } 414 415 fireStockItemsAdded(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 416 } 417 418 /** 419 * Receive the event from the source Stock, translate and propagate it to any listeners. 420 * 421 * @override Never 422 */ 423 public void commitAddStockItems(StockChangeEvent<T, CT> e) { 424 Set<T> stItems = new HashSet<T>(); 425 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 426 T si = i.next(); 427 428 if (contains(si, e.getBasket())) { 429 stItems.add(si); 430 } 431 } 432 433 fireStockItemsAddCommit(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 434 } 435 436 /** 437 * Receive the event from the source Stock, translate and propagate it to any listeners. 438 * 439 * @override Never 440 */ 441 public void rollbackAddStockItems(StockChangeEvent<T, CT> e) { 442 Set<T> stItems = new HashSet<T>(); 443 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 444 stItems.add(i.next()); 445 } 446 447 fireStockItemsAddRollback(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 448 } 449 450 /** 451 * Receive the event from the source Stock, translate and propagate it to any listeners. 452 * 453 * @override Never 454 */ 455 public void canRemoveStockItems(StockChangeEvent<T, CT> e) throws VetoException { 456 Set<T> stItems = new HashSet<T>(); 457 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 458 T si = i.next(); 459 460 if (contains(si, e.getBasket())) { 461 stItems.add(si); 462 } 463 } 464 465 fireCanRemoveStockItems(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 466 } 467 468 /** 469 * Receive the event from the source Stock, translate and propagate it to any listeners. 470 * 471 * @override Never 472 */ 473 public void noRemoveStockItems(StockChangeEvent<T, CT> e) { 474 Set<T> stItems = new HashSet<T>(); 475 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 476 T si = i.next(); 477 478 if (contains(si, e.getBasket())) { 479 stItems.add(si); 480 } 481 } 482 483 fireStockItemsNoRemove(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 484 } 485 486 /** 487 * Receive the event from the source Stock, translate and propagate it to any listeners. 488 * 489 * @override Never 490 */ 491 public void removedStockItems(StockChangeEvent<T, CT> e) { 492 Set<T> stItems = new HashSet<T>(); 493 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 494 stItems.add(i.next()); 495 } 496 497 fireStockItemsRemoved(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 498 } 499 500 /** 501 * Receive the event from the source Stock, translate and propagate it to any listeners. 502 * 503 * @override Never 504 */ 505 public void commitRemoveStockItems(StockChangeEvent<T, CT> e) { 506 Set<T> stItems = new HashSet<T>(); 507 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 508 stItems.add(i.next()); 509 } 510 511 fireStockItemsRemoveCommit(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 512 } 513 514 /** 515 * Receive the event from the source Stock, translate and propagate it to any listeners. 516 * 517 * @override Never 518 */ 519 public void rollbackRemoveStockItems(StockChangeEvent<T, CT> e) { 520 Set<T> stItems = new HashSet<T>(); 521 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 522 T si = i.next(); 523 524 if (contains(si, e.getBasket())) { 525 stItems.add(si); 526 } 527 } 528 529 fireStockItemsRemoveRollback(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 530 } 531 532 /** 533 * Receive the event from the source Stock, translate and propagate it to any listeners. 534 * 535 * @override Never 536 */ 537 public void canEditStockItems(StockChangeEvent<T, CT> e) throws VetoException { 538 Set<T> stItems = new HashSet<T>(); 539 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 540 T si = i.next(); 541 542 if (contains(si, e.getBasket())) { 543 stItems.add(si); 544 } 545 } 546 547 fireCanEditStockItems(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 548 } 549 550 /** 551 * Receive the event from the source Stock, translate and propagate it to any listeners. 552 * 553 * @override Never 554 */ 555 public void noEditStockItems(StockChangeEvent<T, CT> e) { 556 Set<T> stItems = new HashSet<T>(); 557 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 558 T si = i.next(); 559 560 if (contains(si, e.getBasket())) { 561 stItems.add(si); 562 } 563 } 564 565 fireStockItemsNoEdit(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 566 } 567 568 /** 569 * Receive the event from the source Stock, translate and propagate it to any listeners. 570 * 571 * @override Never 572 */ 573 public void editingStockItems(StockChangeEvent<T, CT> e) { 574 Set<T> stItems = new HashSet<T>(); 575 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 576 T si = i.next(); 577 578 if (contains(si, e.getBasket())) { 579 stItems.add(si); 580 } 581 } 582 583 fireEditingStockItems(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 584 } 585 586 /** 587 * Receive the event from the source Stock, translate and propagate it to any listeners. 588 * 589 * @override Never 590 */ 591 public void commitEditStockItems(StockChangeEvent<T, CT> e) { 592 Set<T> stItems = new HashSet<T>(); 593 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 594 T si = i.next(); 595 596 if (contains(si, e.getBasket())) { 597 stItems.add(si); 598 } 599 } 600 601 fireStockItemsEditCommit(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 602 } 603 604 /** 605 * Receive the event from the source Stock, translate and propagate it to any listeners. 606 * 607 * @override Never 608 */ 609 public void rollbackEditStockItems(StockChangeEvent<T, CT> e) { 610 Set<T> stItems = new HashSet<T>(); 611 for (Iterator<T> i = e.getAffectedItems(); i.hasNext(); ) { 612 T si = i.next(); 613 614 if (contains(si, e.getBasket())) { 615 stItems.add(si); 616 } 617 } 618 619 fireStockItemsEditRollback(new StockFilterEvent<T, CT>(this, e.getAffectedKey(), stItems, e.getBasket())); 620 } 621 622 /** 623 * Fire an event to any listeners. 624 * 625 * @override Never 626 */ 627 @SuppressWarnings("unchecked") 628 protected void fireStockItemsAdded(StockChangeEvent<T, CT> e) { 629 Object[] listeners = m_lhListeners.getListenerList(); 630 631 for (int i = listeners.length - 2; i >= 0; i -= 2) { 632 if (listeners[i] == StockChangeListener.class) { 633 634 ((StockChangeListener)listeners[i + 1]).addedStockItems(e); 635 } 636 } 637 } 638 639 /** 640 * Fire an event to any listeners. 641 * 642 * @override Never 643 */ 644 @SuppressWarnings("unchecked") 645 protected void fireStockItemsAddCommit(StockChangeEvent<T, CT> e) { 646 Object[] listeners = m_lhListeners.getListenerList(); 647 648 for (int i = listeners.length - 2; i >= 0; i -= 2) { 649 if (listeners[i] == StockChangeListener.class) { 650 651 ((StockChangeListener)listeners[i + 1]).commitAddStockItems(e); 652 } 653 } 654 } 655 656 /** 657 * Fire an event to any listeners. 658 * 659 * @override Never 660 */ 661 @SuppressWarnings("unchecked") 662 protected void fireStockItemsAddRollback(StockChangeEvent<T, CT> e) { 663 Object[] listeners = m_lhListeners.getListenerList(); 664 665 for (int i = listeners.length - 2; i >= 0; i -= 2) { 666 if (listeners[i] == StockChangeListener.class) { 667 668 ((StockChangeListener)listeners[i + 1]).rollbackAddStockItems(e); 669 } 670 } 671 } 672 673 /** 674 * Fire an event to any listeners. 675 * 676 * @override Never 677 */ 678 @SuppressWarnings("unchecked") 679 protected void fireStockItemsNoRemove(StockChangeEvent<T, CT> e) { 680 Object[] listeners = m_lhListeners.getListenerList(); 681 682 for (int i = listeners.length - 2; i >= 0; i -= 2) { 683 if (listeners[i] == StockChangeListener.class) { 684 685 ((StockChangeListener)listeners[i + 1]).noRemoveStockItems(e); 686 } 687 } 688 } 689 690 /** 691 * Fire an event to any listeners. 692 * 693 * @override Never 694 */ 695 @SuppressWarnings("unchecked") 696 protected void fireStockItemsRemoved(StockChangeEvent<T, CT> e) { 697 Object[] listeners = m_lhListeners.getListenerList(); 698 699 for (int i = listeners.length - 2; i >= 0; i -= 2) { 700 if (listeners[i] == StockChangeListener.class) { 701 702 ((StockChangeListener)listeners[i + 1]).removedStockItems(e); 703 } 704 } 705 } 706 707 /** 708 * Fire an event to any listeners. 709 * 710 * @override Never 711 */ 712 @SuppressWarnings("unchecked") 713 protected void fireStockItemsRemoveCommit(StockChangeEvent<T, CT> e) { 714 Object[] listeners = m_lhListeners.getListenerList(); 715 716 for (int i = listeners.length - 2; i >= 0; i -= 2) { 717 if (listeners[i] == StockChangeListener.class) { 718 719 ((StockChangeListener)listeners[i + 1]).commitRemoveStockItems(e); 720 } 721 } 722 } 723 724 /** 725 * Fire an event to any listeners. 726 * 727 * @override Never 728 */ 729 @SuppressWarnings("unchecked") 730 protected void fireStockItemsRemoveRollback(StockChangeEvent<T, CT> e) { 731 Object[] listeners = m_lhListeners.getListenerList(); 732 733 for (int i = listeners.length - 2; i >= 0; i -= 2) { 734 if (listeners[i] == StockChangeListener.class) { 735 736 ((StockChangeListener)listeners[i + 1]).rollbackRemoveStockItems(e); 737 } 738 } 739 } 740 741 /** 742 * Fire an event to any listeners. 743 * 744 * @override Never 745 */ 746 @SuppressWarnings("unchecked") 747 protected void fireCanRemoveStockItems(StockChangeEvent<T, CT> e) throws VetoException { 748 Object[] listeners = m_lhListeners.getListenerList(); 749 750 for (int i = listeners.length - 2; i >= 0; i -= 2) { 751 if (listeners[i] == StockChangeListener.class) { 752 ((StockChangeListener)listeners[i + 1]).canRemoveStockItems(e); 753 } 754 } 755 } 756 757 /** 758 * Fire an event to any listeners. 759 * 760 * @override Never 761 */ 762 @SuppressWarnings("unchecked") 763 protected void fireCanEditStockItems(StockChangeEvent<T, CT> e) throws VetoException { 764 Object[] listeners = m_lhListeners.getListenerList(); 765 766 for (int i = listeners.length - 2; i >= 0; i -= 2) { 767 if (listeners[i] == StockChangeListener.class) { 768 ((StockChangeListener)listeners[i + 1]).canEditStockItems(e); 769 } 770 } 771 } 772 773 /** 774 * Fire an event to any listeners. 775 * 776 * @override Never 777 */ 778 @SuppressWarnings("unchecked") 779 protected void fireStockItemsNoEdit(StockChangeEvent<T, CT> e) { 780 Object[] listeners = m_lhListeners.getListenerList(); 781 782 for (int i = listeners.length - 2; i >= 0; i -= 2) { 783 if (listeners[i] == StockChangeListener.class) { 784 785 ((StockChangeListener)listeners[i + 1]).noEditStockItems(e); 786 } 787 } 788 } 789 790 /** 791 * Fire an event to any listeners. 792 * 793 * @override Never 794 */ 795 @SuppressWarnings("unchecked") 796 protected void fireEditingStockItems(StockChangeEvent<T, CT> e) { 797 Object[] listeners = m_lhListeners.getListenerList(); 798 799 for (int i = listeners.length - 2; i >= 0; i -= 2) { 800 if (listeners[i] == StockChangeListener.class) { 801 802 ((StockChangeListener)listeners[i + 1]).editingStockItems(e); 803 } 804 } 805 } 806 807 /** 808 * Fire an event to any listeners. 809 * 810 * @override Never 811 */ 812 @SuppressWarnings("unchecked") 813 protected void fireStockItemsEditCommit(StockChangeEvent<T, CT> e) { 814 Object[] listeners = m_lhListeners.getListenerList(); 815 816 for (int i = listeners.length - 2; i >= 0; i -= 2) { 817 if (listeners[i] == StockChangeListener.class) { 818 819 ((StockChangeListener)listeners[i + 1]).commitEditStockItems(e); 820 } 821 } 822 } 823 824 /** 825 * Fire an event to any listeners. 826 * 827 * @override Never 828 */ 829 @SuppressWarnings("unchecked") 830 protected void fireStockItemsEditRollback(StockChangeEvent<T, CT> e) { 831 Object[] listeners = m_lhListeners.getListenerList(); 832 833 for (int i = listeners.length - 2; i >= 0; i -= 2) { 834 if (listeners[i] == StockChangeListener.class) { 835 836 ((StockChangeListener)listeners[i + 1]).rollbackEditStockItems(e); 837 } 838 } 839 } 840 }