ca.odell.glazedlists.BasicEventList Maven / Gradle / Ivy
Show all versions of glazedlists_java15 Show documentation
/* Glazed Lists (c) 2003-2006 */
/* http://publicobject.com/glazedlists/ publicobject.com,*/
/* O'Dell Engineering Ltd.*/
package ca.odell.glazedlists;
// concurrency is similar to java.util.concurrent in J2SE 1.5
import ca.odell.glazedlists.util.concurrent.*;
import ca.odell.glazedlists.event.ListEventListener;
import ca.odell.glazedlists.event.ListEventPublisher;
// Java collections are used for underlying data storage
import java.util.*;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
/**
* An {@link EventList} that wraps any simple {@link List}, such as {@link ArrayList}
* or {@link LinkedList}.
*
* Unlike most {@link EventList}s, this class is {@link Serializable}. When
* {@link BasicEventList} is serialized, all of its elements are serialized
* and all of its listeners that implement {@link Serializable}. Upon
* deserialization, the new copy uses a different {@link #getReadWriteLock() lock}
* than its source {@link BasicEventList}.
*
*
* EventList Overview
* Writable: yes
* Concurrency: thread ready, not thread safe
* Performance: reads: O(1), writes O(1) amortized
* Memory: O(N)
* Unit Tests: N/A
* Issues: N/A
*
*
* @author Jesse Wilson
*/
public final class BasicEventList extends AbstractEventList implements Serializable {
/** For versioning as a {@link Serializable} */
private static final long serialVersionUID = 4883958173323072345L;
/** the underlying data list */
private List data;
/**
* Creates a {@link BasicEventList}.
*/
public BasicEventList() {
this(LockFactory.DEFAULT.createReadWriteLock());
}
/**
* Creates a {@link BasicEventList} that uses the specified {@link ReadWriteLock}
* for concurrent access.
*/
public BasicEventList(ReadWriteLock readWriteLock) {
super(null);
this.data = new ArrayList();
this.readWriteLock = readWriteLock;
}
/**
* Creates an empty {@link BasicEventList} with the given
* initialCapacity
.
*/
public BasicEventList(int initalCapacity) {
super(null);
this.data = new ArrayList(initalCapacity);
this.readWriteLock = LockFactory.DEFAULT.createReadWriteLock();
}
/**
* Creates a {@link BasicEventList} that uses the specified {@link List} as
* the underlying implementation.
*
* Warning: all editing to
* the specified {@link List} must be done through via this
* {@link BasicEventList} interface. Otherwise this {@link BasicEventList} will
* become out of sync and operations will fail.
*
* @deprecated As of 2005/03/06, this constructor has been declared unsafe
* because the source list is exposed. This allows it to be modified without
* the required events being fired. This constructor has been replaced by
* the factory method {@link GlazedLists#eventList(Collection)}.
*/
public BasicEventList(List list) {
super(null);
this.data = list;
this.readWriteLock = LockFactory.DEFAULT.createReadWriteLock();
}
/**
* Creates a {@link BasicEventList} using the specified
* {@link ListEventPublisher} and {@link ReadWriteLock}.
*
* @since 2006-June-12
*/
public BasicEventList(ListEventPublisher publisher, ReadWriteLock readWriteLock) {
super(publisher);
this.data = new ArrayList();
this.readWriteLock = readWriteLock;
}
/** {@inheritDoc} */
public void add(int index, E element) {
// create the change event
updates.beginEvent();
updates.addInsert(index);
// do the actual add
data.add(index, element);
// fire the event
updates.commitEvent();
}
/** {@inheritDoc} */
public boolean add(E element) {
// create the change event
updates.beginEvent();
updates.addInsert(size());
// do the actual add
boolean result = data.add(element);
// fire the event
updates.commitEvent();
return result;
}
/** {@inheritDoc} */
public boolean addAll(Collection extends E> collection) {
return addAll(size(), collection);
}
/** {@inheritDoc} */
public boolean addAll(int index, Collection extends E> collection) {
// don't do an add of an empty set
if(collection.size() == 0) return false;
// create the change event
updates.beginEvent();
updates.addInsert(index, index + collection.size() - 1);
// do the actual add
boolean result = data.addAll(index, collection);
// fire the event
updates.commitEvent();
return result;
}
/** {@inheritDoc} */
public E remove(int index) {
// create the change event
updates.beginEvent();
updates.addDelete(index);
// do the actual remove
E removed = data.remove(index);
// fire the event
updates.commitEvent();
return removed;
}
/** {@inheritDoc} */
public boolean remove(Object element) {
int index = data.indexOf(element);
if(index == -1) return false;
remove(index);
return true;
}
/** {@inheritDoc} */
public void clear() {
// don't do a clear on an empty set
if(isEmpty()) return;
// create the change event
updates.beginEvent();
updates.addDelete(0, size() - 1);
// do the actual clear
data.clear();
// fire the event
updates.commitEvent();
}
/** {@inheritDoc} */
public E set(int index, E element) {
// create the change event
updates.beginEvent();
updates.addUpdate(index);
// do the actual set
E previous = data.set(index, element);
// fire the event
updates.commitEvent();
return previous;
}
/** {@inheritDoc} */
public E get(int index) {
return data.get(index);
}
/** {@inheritDoc} */
public int size() {
return data.size();
}
/** {@inheritDoc} */
public boolean removeAll(Collection> collection) {
boolean changed = false;
updates.beginEvent();
for(Iterator i = collection.iterator(); i.hasNext(); ) {
Object value = i.next();
int index = -1;
while((index = indexOf(value)) != -1) {
updates.addDelete(index);
data.remove(index);
changed = true;
}
}
updates.commitEvent();
return changed;
}
/** {@inheritDoc} */
public boolean retainAll(Collection> collection) {
boolean changed = false;
updates.beginEvent();
int index = 0;
while(index < data.size()) {
if(collection.contains(data.get(index))) {
index++;
} else {
updates.addDelete(index);
data.remove(index);
changed = true;
}
}
updates.commitEvent();
return changed;
}
/**
* Although {@link EventList}s are not in general, {@link BasicEventList} is
* {@link Serializable}. All of the {@link ListEventListener}s that are themselves
* {@link Serializable} will be serialized, but others will not. Note that there
* is no easy way to access the {@link ListEventListener}s of
* an {@link EventList}, particularly after it has been serialized.
*
* As of October 3, 2005, this is the wire format of serialized
* {@link BasicEventList}s:
*
An Object[]
containing each of the list's elements
* A ListEventListener[]
containing only the
* listeners that themselves implement {@link Serializable}. Those that
* do not will not be serialized. Note that {@link TransformedList}s
* such as {@link FilterList} are not {@link Serializable} and will not
* be serialized.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
// 1. The elements to write
E[] elements = (E[])data.toArray(new Object[size()]);
// 2. The Listeners to write
List> serializableListeners = new ArrayList>(1);
for(Iterator> i = updates.getListEventListeners().iterator(); i.hasNext(); ) {
ListEventListener listener = i.next();
if(!(listener instanceof Serializable)) continue;
serializableListeners.add(listener);
}
ListEventListener[] listeners = serializableListeners.toArray(new ListEventListener[serializableListeners.size()]);
// 3. Write the listeners and elements
out.writeObject(elements);
out.writeObject(listeners);
}
/**
* Peer method to {@link #writeObject(ObjectOutputStream)}. Note that this
* is functionally equivalent to a constructor and should validate that
* everything is in place including locks, etc.
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// 1. Prepare the EventList helper members
this.readWriteLock = LockFactory.DEFAULT.createReadWriteLock();
// 2. Read in the elements
E[] elements = (E[])in.readObject();
ListEventListener[] listeners = (ListEventListener[])in.readObject();
// 3. Populate the EventList data
this.data = new ArrayList();
this.data.addAll(Arrays.asList(elements));
// 4. Populate the listeners
for(int i = 0; i < listeners.length; i++) {
this.updates.addListEventListener(listeners[i]);
}
}
}