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.Collection;
028    import java.util.IdentityHashMap;
029    import java.util.Iterator;
030    import java.util.List;
031    import java.util.ListIterator;
032    import java.util.Map;
033    import java.util.Set;
034    
035    import javafx.beans.InvalidationListener;
036    import javafx.collections.FXCollections;
037    import javafx.collections.ListChangeListener;
038    import javafx.collections.ObservableList;
039    
040    import org.granite.client.persistence.LazyableCollection;
041    import org.granite.logging.Logger;
042    import org.granite.messaging.amf.RemoteClass;
043    
044    /**
045     * @author William DRAI
046     */
047    @RemoteClass("org.granite.messaging.persistence.ExternalizablePersistentBag")
048    public class PersistentBag<T> implements Set<T>, ObservableList<T>, LazyableCollection, Externalizable {
049            
050            @SuppressWarnings("unused")
051            private static final Logger log = Logger.getLogger(PersistentBag.class);
052    
053        @SuppressWarnings("unused")
054            private boolean initializing = false;
055        private boolean initialized = false;
056        private String metadata = null;
057        private boolean dirty = false;
058        
059        private ObservableList<T> oset;
060       
061        private ListChangeListener<T> listener = new ListChangeListener<T>() {
062            public void onChanged(ListChangeListener.Change<? extends T> change) {
063                if (!initialized)
064                    return;
065                while (change.next()) {
066                    if (change.wasAdded() || change.wasRemoved() || change.wasReplaced() || change.wasPermutated()) {
067                        dirty = true;
068                        break;
069                    }
070                }
071            }
072        };
073    
074        
075        public PersistentBag() {
076            this.oset = FXCollections.observableArrayList();
077            this.initialized = true;
078            addListener(listener);
079        }
080    
081        public PersistentBag(Set<T> set) {
082            this.oset = FXCollections.observableArrayList(set);
083            this.initialized = true;
084            addListener(listener);
085        }
086        
087        public PersistentBag(boolean initialized) {
088            this.oset = FXCollections.observableArrayList();
089            this.initialized = initialized;         
090            if (initialized)
091                addListener(listener);
092        }
093    
094    
095        public final boolean isInitialized() {
096            return initialized;
097        }
098    
099        public void initializing() {
100            clear();
101            initializing = true;
102            dirty = false;
103            removeListener(listener);
104        }
105    
106        public void initialize() {
107            initializing = false;
108            initialized = true;
109            dirty = false;
110            addListener(listener);
111        }
112    
113        public void uninitialize() {
114            removeListener(listener);
115            initialized = false;
116            clear();
117            dirty = false;
118        }
119        
120        public PersistentBag<T> clone(boolean uninitialize) {
121            PersistentBag<T> coll = new PersistentBag<T>(initialized && !uninitialize);
122            coll.metadata = metadata;
123            if (initialized) {
124                for (T obj : this)
125                    coll.add(obj);
126            }
127            coll.dirty = dirty;
128            return coll; 
129        }
130    
131        public void addListener(InvalidationListener listener) {
132            oset.addListener(listener);
133        }
134    
135        public void removeListener(InvalidationListener listener) {
136            oset.removeListener(listener);
137        }
138        
139        private Map<ListChangeListener<? super T>, ListChangeListener<? super T>> listenerWrappers = new IdentityHashMap<ListChangeListener<? super T>, ListChangeListener<? super T>>();
140    
141        @SuppressWarnings({ "unchecked", "rawtypes" })
142            public void addListener(ListChangeListener<? super T> listener) {
143            ListChangeListener<? super T> listenerWrapper = new ListChangeListenerWrapper(this, listener);
144            listenerWrappers.put(listener, listenerWrapper);
145            oset.addListener(listenerWrapper);
146        }
147    
148            public void removeListener(ListChangeListener<? super T> listener) {
149            ListChangeListener<? super T> listenerWrapper = listenerWrappers.remove(listener);
150            if (listenerWrapper != null)
151                    oset.removeListener(listenerWrapper);
152        }
153        
154    
155        public boolean isEmpty() {
156            return oset.isEmpty();
157        }
158    
159        public boolean contains(Object o) {
160            return oset.contains(o);
161        }
162    
163        public Iterator<T> iterator() {
164            return oset.iterator();
165        }
166    
167        public boolean add(T e) {
168            return oset.add(e);
169        }
170    
171        public boolean remove(Object o) {
172            return oset.remove(o);
173        }
174    
175        public boolean containsAll(Collection<?> c) {
176            return oset.containsAll(c);
177        }
178    
179        public boolean addAll(Collection<? extends T> c) {
180            return oset.addAll(c);
181        }
182    
183        public boolean addAll(int index, Collection<? extends T> c) {
184            return oset.addAll(index, c);
185        }
186    
187        public boolean removeAll(Collection<?> c) {
188            return oset.removeAll(c);
189        }
190    
191        public boolean equals(Object o) {
192            return oset.equals(o);
193        }
194    
195        public int hashCode() {
196            return oset.hashCode();
197        }
198    
199        public T get(int index) {
200            return oset.get(index);
201        }
202    
203        public void add(int index, T element) {
204            oset.add(index, element);
205        }
206    
207        public boolean addAll(T... elements) {
208            return oset.addAll(elements);
209        }
210        
211        public void clear() {
212            oset.clear();
213        }
214    
215        public int indexOf(Object o) {
216            return oset.indexOf(o);
217        }
218    
219        public int lastIndexOf(Object o) {
220            return oset.lastIndexOf(o);
221        }
222    
223        public ListIterator<T> listIterator() {
224            return oset.listIterator();
225        }
226    
227        public ListIterator<T> listIterator(int index) {
228            return oset.listIterator(index);
229        }
230    
231        public void remove(int arg0, int arg1) {
232            oset.remove(arg0, arg1);
233        }
234    
235        public T remove(int index) {
236            return oset.remove(index);
237        }
238    
239        public boolean removeAll(T... elements) {
240            return oset.removeAll(elements);
241        }
242    
243        public boolean retainAll(Collection<?> c) {
244            return oset.retainAll(c);
245        }
246    
247        public boolean retainAll(T... elements) {
248            return oset.retainAll(elements);
249        }
250    
251        public T set(int index, T element) {
252            return oset.set(index, element);
253        }
254    
255        public boolean setAll(Collection<? extends T> coll) {
256            return oset.setAll(coll);
257        }
258    
259        public boolean setAll(T... arg0) {
260            return oset.setAll(arg0);
261        }
262    
263        public int size() {
264            return oset.size();
265        }
266    
267        public Object[] toArray() {
268            return oset.toArray();
269        }
270    
271        @SuppressWarnings("hiding")
272            public <T> T[] toArray(T[] a) {
273            return oset.toArray(a);
274        }
275    
276        public List<T> subList(int fromIndex, int toIndex) {
277            return oset.subList(fromIndex, toIndex);
278        }
279        
280        @Override
281        public String toString() {
282            return getClass().getSimpleName() + (initialized ? "" : " (uninitialized)") + (dirty ? " (dirty)" : "") + ":" + oset.toString();
283        }
284    
285        @SuppressWarnings("unchecked")
286        public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException {
287            initialized = ((Boolean)input.readObject()).booleanValue();
288            metadata = (String)input.readObject();
289            if (initialized) {
290                dirty = ((Boolean)input.readObject()).booleanValue();
291                T[] array = (T[])input.readObject();
292                oset = FXCollections.observableArrayList(array);
293            }
294        }
295    
296        public void writeExternal(ObjectOutput output) throws IOException {
297            output.writeObject(Boolean.valueOf(initialized));
298            output.writeObject(metadata);
299            if (initialized) {
300                output.writeObject(Boolean.valueOf(dirty));
301                output.writeObject(oset.toArray());
302            }
303        }
304    }