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 }