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    }