001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.client.persistence.javafx;
022    
023    import java.io.Externalizable;
024    import java.io.IOException;
025    import java.io.ObjectInput;
026    import java.io.ObjectOutput;
027    import java.util.ArrayList;
028    import java.util.Arrays;
029    import java.util.Collection;
030    import java.util.IdentityHashMap;
031    import java.util.Iterator;
032    import java.util.List;
033    import java.util.ListIterator;
034    import java.util.Map;
035    import java.util.Set;
036    
037    import javafx.beans.InvalidationListener;
038    import javafx.collections.FXCollections;
039    import javafx.collections.ListChangeListener;
040    import javafx.collections.ObservableList;
041    
042    import org.granite.logging.Logger;
043    import org.granite.messaging.amf.RemoteClass;
044    import org.granite.client.persistence.LazyableCollection;
045    
046    /**
047     * @author William DRAI
048     */
049    @RemoteClass("org.granite.messaging.persistence.ExternalizablePersistentSet")
050    public class PersistentSet<T> implements Set<T>, ObservableList<T>, LazyableCollection, Externalizable {
051            
052            @SuppressWarnings("unused")
053            private static final Logger log = Logger.getLogger(PersistentSet.class);
054    
055        @SuppressWarnings("unused")
056            private boolean initializing = false;
057        private boolean initialized = false;
058        private String metadata = null;
059        private boolean dirty = false;
060        
061        private ObservableList<T> oset;
062       
063        private ListChangeListener<T> listener = new ListChangeListener<T>() {
064            public void onChanged(ListChangeListener.Change<? extends T> change) {
065                if (!initialized)
066                    return;
067                while (change.next()) {
068                    if (change.wasAdded() || change.wasRemoved() || change.wasReplaced() || change.wasPermutated()) {
069                        dirty = true;
070                        break;
071                    }
072                }
073            }
074        };
075    
076        
077        public PersistentSet() {
078            this.oset = FXCollections.observableArrayList();
079            this.initialized = true;
080            this.oset.addListener(listener);
081        }
082    
083        public PersistentSet(Set<T> set) {
084            this.oset = FXCollections.observableArrayList(set);
085            this.initialized = true;
086            this.oset.addListener(listener);
087        }
088        
089        public PersistentSet(boolean initialized) {
090            this.oset = FXCollections.observableArrayList();
091            this.initialized = initialized;         
092            if (initialized)
093                this.oset.addListener(listener);
094        }
095    
096    
097        public final boolean isInitialized() {
098            return initialized;
099        }
100    
101        public void initializing() {
102            clear();
103            initializing = true;
104            dirty = false;
105            oset.removeListener(listener);
106        }
107    
108        public void initialize() {
109            initializing = false;
110            initialized = true;
111            dirty = false;
112            oset.addListener(listener);
113        }
114    
115        public void uninitialize() {
116            oset.removeListener(listener);
117            initialized = false;
118            clear();
119            dirty = false;
120        }
121        
122        public PersistentSet<T> clone(boolean uninitialize) {
123            PersistentSet<T> coll = new PersistentSet<T>(initialized && !uninitialize);
124            coll.metadata = metadata;
125            if (initialized) {
126                for (T obj : this)
127                    coll.add(obj);
128            }
129            coll.dirty = dirty;
130            return coll; 
131        }
132        
133        public void addListener(InvalidationListener listener) {
134            oset.addListener(listener);
135        }
136    
137        public void removeListener(InvalidationListener listener) {
138            oset.removeListener(listener);
139        }
140        
141        private Map<ListChangeListener<? super T>, ListChangeListener<? super T>> listenerWrappers = new IdentityHashMap<ListChangeListener<? super T>, ListChangeListener<? super T>>();
142    
143        @SuppressWarnings({ "unchecked", "rawtypes" })
144            public void addListener(ListChangeListener<? super T> listener) {
145            ListChangeListener<? super T> listenerWrapper = new ListChangeListenerWrapper(this, listener);
146            listenerWrappers.put(listener, listenerWrapper);
147            oset.addListener(listenerWrapper);
148        }
149    
150        public void removeListener(ListChangeListener<? super T> listener) {
151            ListChangeListener<? super T> listenerWrapper = listenerWrappers.remove(listener);
152            if (listenerWrapper != null)
153                    oset.removeListener(listenerWrapper);
154        }
155        
156        public boolean isEmpty() {
157            return oset.isEmpty();
158        }
159    
160        public boolean contains(Object o) {
161            return oset.contains(o);
162        }
163    
164        public Iterator<T> iterator() {
165            return oset.iterator();
166        }
167    
168        public boolean add(T e) {
169            return oset.add(e);
170        }
171    
172        public boolean remove(Object o) {
173            return oset.remove(o);
174        }
175    
176        public boolean containsAll(Collection<?> c) {
177            return oset.containsAll(c);
178        }
179    
180        public boolean addAll(Collection<? extends T> c) {
181            List<T> toAdd = new ArrayList<T>(c);
182            toAdd.removeAll(oset);
183            return oset.addAll(toAdd);
184        }
185    
186        public boolean addAll(int index, Collection<? extends T> c) {
187            List<T> toAdd = new ArrayList<T>(c);
188            toAdd.removeAll(oset);
189            return oset.addAll(index, toAdd);
190        }
191    
192        public boolean removeAll(Collection<?> c) {
193            return oset.removeAll(c);
194        }
195    
196        public boolean equals(Object o) {
197            return oset.equals(o);
198        }
199    
200        public int hashCode() {
201            return oset.hashCode();
202        }
203    
204        public T get(int index) {
205            return oset.get(index);
206        }
207    
208        public void add(int index, T element) {
209            oset.add(index, element);
210        }
211    
212        public boolean addAll(T... elements) {
213            List<T> toAdd = Arrays.asList(elements);
214            toAdd.removeAll(oset);
215            return oset.addAll(toAdd);
216        }
217    
218        public void clear() {
219            oset.clear();
220        }
221    
222        public int indexOf(Object o) {
223            return oset.indexOf(o);
224        }
225    
226        public int lastIndexOf(Object o) {
227            return oset.lastIndexOf(o);
228        }
229    
230        public ListIterator<T> listIterator() {
231            return oset.listIterator();
232        }
233    
234        public ListIterator<T> listIterator(int index) {
235            return oset.listIterator(index);
236        }
237    
238        public void remove(int arg0, int arg1) {
239            oset.remove(arg0, arg1);
240        }
241    
242        public T remove(int index) {
243            return oset.remove(index);
244        }
245    
246        public boolean removeAll(T... elements) {
247            return oset.removeAll(elements);
248        }
249    
250        public boolean retainAll(Collection<?> c) {
251            return oset.retainAll(c);
252        }
253    
254        public boolean retainAll(T... elements) {
255            return oset.retainAll(elements);
256        }
257    
258        public T set(int index, T element) {
259            return oset.set(index, element);
260        }
261    
262        public boolean setAll(Collection<? extends T> coll) {
263            return oset.setAll(coll);
264        }
265    
266        public boolean setAll(T... arg0) {
267            return oset.setAll(arg0);
268        }
269    
270        public int size() {
271            return oset.size();
272        }
273    
274        public Object[] toArray() {
275            return oset.toArray();
276        }
277    
278        @SuppressWarnings("hiding")
279            public <T> T[] toArray(T[] a) {
280            return oset.toArray(a);
281        }
282    
283        public List<T> subList(int fromIndex, int toIndex) {
284            return oset.subList(fromIndex, toIndex);
285        }
286        
287        @Override
288        public String toString() {
289            return getClass().getSimpleName() + (initialized ? "" : " (uninitialized)") + (dirty ? " (dirty)" : "") + ":" + oset.toString();
290        }
291    
292        @SuppressWarnings("unchecked")
293        public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException {
294            initialized = ((Boolean)input.readObject()).booleanValue();
295            metadata = (String)input.readObject();
296            if (initialized) {
297                dirty = ((Boolean)input.readObject()).booleanValue();
298                T[] array = (T[])input.readObject();
299                oset = FXCollections.observableArrayList(array);
300            }
301        }
302    
303        public void writeExternal(ObjectOutput output) throws IOException {
304            output.writeObject(Boolean.valueOf(initialized));
305            output.writeObject(metadata);
306            if (initialized) {
307                output.writeObject(Boolean.valueOf(dirty));
308                output.writeObject(oset.toArray());
309            }
310        }
311    }