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