001    // GraphLab Project: http://graphlab.sharif.edu
002    // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
003    // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/
004    
005    package graphlab.platform.attribute;
006    
007    import java.util.Collection;
008    import java.util.Iterator;
009    import java.util.Map;
010    
011    /**
012     * A handy NotifiableSet which acts on any AttributeSet and converts it to a NotifiableAttributeSet,
013     * This is done by checking the AttributeSet for changes in each (100) mili seconds.
014     * changes on (T) input will take effect on next 100 milisecond,
015     * using this class should be done with care, this class uses a thread
016     * and checks the edge on each 100ms for any changes, so creating a lot of
017     * instances of this class (for example for all edges of graph)
018     * will take more and more cpu,
019     * <p/>
020     * try to create as few as possible instances of this class and call stop() when you don't need
021     * it any more!
022     * <p/>
023     */
024    public class TimeLimitedNotifiableAttrSet<T extends AttributeSet> implements Runnable, NotifiableAttributeSet {
025        private boolean started = false;
026        private long millis = 100;
027        Thread thread;
028        private T inp;
029        NotifiableAttributeSetImpl as = new NotifiableAttributeSetImpl();
030    
031        public TimeLimitedNotifiableAttrSet(T input) {
032            this.inp = input;
033            thread = new Thread(this);
034        }
035    
036        /**
037         * starts firinig listeners to this class
038         */
039        public void start() {
040            started = true;
041            thread.start();
042        }
043    
044        /**
045         * stops firing listeners
046         */
047        public void stop() {
048            started = false;
049        }
050    
051        /**
052         * -> Thread
053         */
054        public void run() {
055            Map<String, Object> old = inp.getAttrs();
056            Map<String, Object> _new;
057            while (started) {
058                _new = inp.getAttrs();
059                fireChange(old, _new);
060                try {
061                    old = inp.getAttrs();
062                    Thread.sleep(millis);
063                } catch (InterruptedException e1) {
064                    e1.printStackTrace();
065                }
066            }
067        }
068    
069        private void fireChange(Map<String, Object> _new, Map<String, Object> old) {
070            Iterator<Map.Entry<String, Object>> i = old.entrySet().iterator();
071            while (i.hasNext()) {
072                Map.Entry<String, Object> e = i.next();
073                String key = e.getKey();
074                Object value = e.getValue();
075                if (value == null) {
076                    if (!(_new.get(key) == null && _new.containsKey(key))) {
077                        inp.put(key, value);
078    
079                    }
080                } else {
081                    if (!value.equals(_new.get(key))) {
082                        fireAttributeChange(getAttributeListeners(), key, old, value);
083                        inp.put(key, value);
084                        fireAttributeChange(getAttributeListeners(), key, old, value);
085                    }
086                }
087            }
088    
089        }
090    
091    //-----   NotifiableAttributeSet Methods
092    
093        public Map<String, Object> getAttrs() {
094            return inp.getAttrs();
095        }
096    
097        public void put(String name, Object value) {
098            Object old = get(name);
099            inp.put(name, value);
100            fireAttributeChange(getAttributeListeners(), name, old, value);
101        }
102    
103        public Object get(String name) {
104            return inp.get(name);
105        }
106    
107        public void addAttributeListener(AttributeListener attributeListener) {
108            as.addAttributeListener(attributeListener);
109        }
110    
111        public Collection<AttributeListener> getAttributeListeners() {
112            return as.getAttributeListeners();
113        }
114    
115        public void removeAttributeListener(AttributeListener attributeListener) {
116            as.removeAttributeListener(attributeListener);
117        }
118    
119        public void fireAttributeChange(Collection<AttributeListener> listeners, String name, Object oldVal, Object newVal) {
120            if (listeners != null) {
121                for (AttributeListener l : listeners) {
122                    l.attributeUpdated(name, oldVal, newVal);
123                }
124            }
125        }
126    
127    }