package com.avaje.ebean.common;
//import com.avaje.ebean.bean.BeanCollectionAdd;
//import com.avaje.ebean.bean.BeanCollectionLoader;
import com.avaje.ebean.bean.EntityBean;
import java.io.Serializable;
import java.util.*;
/**
* List capable of lazy loading.
*/
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E> {
private static final long serialVersionUID = 1L;
/**
* The underlying List implementation.
*/
private List<E> list;
/**
* Specify the underlying List implementation.
*/
public BeanList(List<E> list) {
super();
this.list = list;
}
/**
* Uses an ArrayList as the underlying List implementation.
*/
public BeanList() {
this(new ArrayList<E>());
}
// @Override
// public boolean isEmptyAndUntouched() {
// return !touched && (list == null || list.isEmpty());
// }
@SuppressWarnings("unchecked")
public void addBean(EntityBean bean) {
list.add((E) bean);
}
@SuppressWarnings("unchecked")
public void internalAdd(Object bean) {
if (list == null) {
list = new ArrayList<E>();
}
list.add((E) bean);
}
public boolean checkEmptyLazyLoad() {
if (list == null) {
list = new ArrayList<E>();
return true;
} else {
return false;
}
}
private void initClear() {
synchronized (this) {
if (list == null) {
if (modifyListening) {
lazyLoadCollection(true);
} else {
list = new ArrayList<E>();
}
}
touched(true);
}
}
private void initAsUntouched() {
init(false);
}
private void init() {
init(true);
}
private void init(boolean setTouched) {
synchronized (this) {
if (list == null) {
lazyLoadCollection(false);
}
touched(setTouched);
}
}
/**
* Set the actual underlying list.
* <p>
* This is primarily for the deferred fetching function.
* </p>
*/
@SuppressWarnings("unchecked")
public void setActualList(List<?> list) {
this.list = (List<E>) list;
}
/**
* Return the actual underlying list.
*/
public List<E> getActualList() {
return list;
}
public Collection<E> getActualDetails() {
return list;
}
// @Override
// public Collection<?> getActualEntries() {
// return list;
// }
/**
* Returns the underlying list.
*/
public Object getActualCollection() {
return list;
}
/**
* Return true if the underlying list is populated.
*/
public boolean isPopulated() {
return list != null;
}
/**
* Return true if this is a reference (lazy loading) bean collection. This is
* the same as !isPopulated();
*/
public boolean isReference() {
return list == null;
}
public String toString() {
StringBuffer sb = new StringBuffer(50);
sb.append("BeanList ");
if (isReadOnly()) {
sb.append("readOnly ");
}
if (list == null) {
sb.append("deferred ");
} else {
sb.append("size[").append(list.size()).append("] ");
sb.append("list").append(list).append("");
}
return sb.toString();
}
/**
* Equal if obj is a List and equal in a list sense.
* <p>
* Specifically obj does not need to be a BeanList but any list. This does not
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
* test.
* </p>
*/
public boolean equals(Object obj) {
init();
return list.equals(obj);
}
public int hashCode() {
init();
return list.hashCode();
}
// -----------------------------------------------------//
// The additional methods are here
// -----------------------------------------------------//
// -----------------------------------------------------//
// proxy method for List
// -----------------------------------------------------//
public void add(int index, E element) {
checkReadOnly();
init();
// if (modifyAddListening) {
// modifyAddition(element);
// }
list.add(index, element);
}
public boolean add(E o) {
checkReadOnly();
init();
// if (modifyAddListening) {
// if (list.add(o)) {
// modifyAddition(o);
// return true;
// } else {
// return false;
// }
// }
return list.add(o);
}
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
// if (modifyAddListening) {
// // all elements in c are added (no contains checking)
// getModifyHolder().modifyAdditionAll(c);
// }
return list.addAll(c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
// if (modifyAddListening) {
// // all elements in c are added (no contains checking)
// getModifyHolder().modifyAdditionAll(c);
// }
return list.addAll(index, c);
}
public void clear() {
checkReadOnly();
// TODO: when clear() and not initialised could be more clever
// and fetch just the Id's
initClear();
// if (modifyRemoveListening) {
// for (int i = 0; i < list.size(); i++) {
// getModifyHolder().modifyRemoval(list.get(i));
// }
// }
list.clear();
}
public boolean contains(Object o) {
init();
return list.contains(o);
}
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(c);
}
public E get(int index) {
init();
return list.get(index);
}
public int indexOf(Object o) {
init();
return list.indexOf(o);
}
public boolean isEmpty() {
initAsUntouched();
return list.isEmpty();
}
public Iterator<E> iterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
// if (modifyListening) {
// Iterator<E> it = list.iterator();
// return new ModifyIterator<E>(this, it);
// }
return list.iterator();
}
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(o);
}
public ListIterator<E> listIterator() {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator());
}
// if (modifyListening) {
// ListIterator<E> it = list.listIterator();
// return new ModifyListIterator<E>(this, it);
// }
return list.listIterator();
}
public ListIterator<E> listIterator(int index) {
init();
if (isReadOnly()) {
return new ReadOnlyListIterator<E>(list.listIterator(index));
}
// if (modifyListening) {
// ListIterator<E> it = list.listIterator(index);
// return new ModifyListIterator<E>(this, it);
// }
return list.listIterator(index);
}
public E remove(int index) {
checkReadOnly();
init();
// if (modifyRemoveListening) {
// E o = list.remove(index);
// modifyRemoval(o);
// return o;
// }
return list.remove(index);
}
public boolean remove(Object o) {
checkReadOnly();
init();
// if (modifyRemoveListening) {
// boolean isRemove = list.remove(o);
// if (isRemove) {
// modifyRemoval(o);
// }
// return isRemove;
// }
return list.remove(o);
}
public boolean removeAll(Collection<?> c) {
checkReadOnly();
init();
// if (modifyRemoveListening) {
// boolean changed = false;
// Iterator<?> it = c.iterator();
// while (it.hasNext()) {
// Object o = (Object) it.next();
// if (list.remove(o)) {
// modifyRemoval(o);
// changed = true;
// }
// }
// return changed;
// }
return list.removeAll(c);
}
public boolean retainAll(Collection<?> c) {
checkReadOnly();
init();
// if (modifyRemoveListening) {
// boolean changed = false;
// Iterator<E> it = list.iterator();
// while (it.hasNext()) {
// Object o = (Object) it.next();
// if (!c.contains(o)) {
// it.remove();
// modifyRemoval(o);
// changed = true;
// }
// }
// return changed;
// }
return list.retainAll(c);
}
public E set(int index, E element) {
checkReadOnly();
init();
// if (modifyListening) {
// E o = list.set(index, element);
// modifyAddition(element);
// modifyRemoval(o);
// return o;
// }
return list.set(index, element);
}
public int size() {
init();
return list.size();
}
public List<E> subList(int fromIndex, int toIndex) {
init();
if (isReadOnly()) {
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
}
// if (modifyListening) {
// return new ModifyList<E>(this, list.subList(fromIndex, toIndex));
// }
return list.subList(fromIndex, toIndex);
}
public Object[] toArray() {
init();
return list.toArray();
}
public <T> T[] toArray(T[] a) {
init();
return list.toArray(a);
}
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
private static final long serialVersionUID = 3097271091406323699L;
private final ListIterator<E> i;
ReadOnlyListIterator(ListIterator<E> i) {
this.i = i;
}
public void add(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void remove() {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public void set(E o) {
throw new IllegalStateException("This collection is in ReadOnly mode");
}
public boolean hasNext() {
return i.hasNext();
}
public boolean hasPrevious() {
return i.hasPrevious();
}
public E next() {
return i.next();
}
public int nextIndex() {
return i.nextIndex();
}
public E previous() {
return i.previous();
}
public int previousIndex() {
return i.previousIndex();
}
}
}