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.ExternalizablePersistentList")
048 public class PersistentList<T> implements ObservableList<T>, LazyableCollection, Externalizable {
049
050 @SuppressWarnings("unused")
051 private static final Logger log = Logger.getLogger(PersistentList.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> olist;
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 PersistentList() {
076 this.olist = FXCollections.observableArrayList();
077 this.initialized = true;
078 addListener(listener);
079 }
080
081 public PersistentList(Set<T> set) {
082 this.olist = FXCollections.observableArrayList(set);
083 this.initialized = true;
084 addListener(listener);
085 }
086
087 public PersistentList(boolean initialized) {
088 this.olist = 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 PersistentList<T> clone(boolean uninitialize) {
121 PersistentList<T> coll = new PersistentList<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 olist.addListener(listener);
133 }
134
135 public void removeListener(InvalidationListener listener) {
136 olist.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 olist.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 olist.removeListener(listenerWrapper);
152 }
153
154
155 public boolean isEmpty() {
156 return olist.isEmpty();
157 }
158
159 public boolean contains(Object o) {
160 return olist.contains(o);
161 }
162
163 public Iterator<T> iterator() {
164 return olist.iterator();
165 }
166
167 public boolean add(T e) {
168 return olist.add(e);
169 }
170
171 public boolean remove(Object o) {
172 return olist.remove(o);
173 }
174
175 public boolean containsAll(Collection<?> c) {
176 return olist.containsAll(c);
177 }
178
179 public boolean addAll(Collection<? extends T> c) {
180 return olist.addAll(c);
181 }
182
183 public boolean addAll(int index, Collection<? extends T> c) {
184 return olist.addAll(index, c);
185 }
186
187 public boolean removeAll(Collection<?> c) {
188 return olist.removeAll(c);
189 }
190
191 public boolean equals(Object o) {
192 return olist.equals(o);
193 }
194
195 public int hashCode() {
196 return olist.hashCode();
197 }
198
199 public T get(int index) {
200 return olist.get(index);
201 }
202
203 public void add(int index, T element) {
204 olist.add(index, element);
205 }
206
207 public boolean addAll(T... elements) {
208 return olist.addAll(elements);
209 }
210
211 public void clear() {
212 olist.clear();
213 }
214
215 public int indexOf(Object o) {
216 return olist.indexOf(o);
217 }
218
219 public int lastIndexOf(Object o) {
220 return olist.lastIndexOf(o);
221 }
222
223 public ListIterator<T> listIterator() {
224 return olist.listIterator();
225 }
226
227 public ListIterator<T> listIterator(int index) {
228 return olist.listIterator(index);
229 }
230
231 public void remove(int arg0, int arg1) {
232 olist.remove(arg0, arg1);
233 }
234
235 public T remove(int index) {
236 return olist.remove(index);
237 }
238
239 public boolean removeAll(T... elements) {
240 return olist.removeAll(elements);
241 }
242
243 public boolean retainAll(Collection<?> c) {
244 return olist.retainAll(c);
245 }
246
247 public boolean retainAll(T... elements) {
248 return olist.retainAll(elements);
249 }
250
251 public T set(int index, T element) {
252 return olist.set(index, element);
253 }
254
255 public boolean setAll(Collection<? extends T> coll) {
256 return olist.setAll(coll);
257 }
258
259 public boolean setAll(T... arg0) {
260 return olist.setAll(arg0);
261 }
262
263 public int size() {
264 return olist.size();
265 }
266
267 public Object[] toArray() {
268 return olist.toArray();
269 }
270
271 @SuppressWarnings("hiding")
272 public <T> T[] toArray(T[] a) {
273 return olist.toArray(a);
274 }
275
276 public List<T> subList(int fromIndex, int toIndex) {
277 return olist.subList(fromIndex, toIndex);
278 }
279
280 @Override
281 public String toString() {
282 return getClass().getSimpleName() + (initialized ? "" : " (uninitialized)") + (dirty ? " (dirty)" : "") + ":" + olist.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 olist = 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(olist.toArray());
302 }
303 }
304 }