//$Id: PersistentList.java 10739 2006-11-06 22:00:41Z [email protected] $
package org.hibernate.collection;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.Type;
/**
* A persistent wrapper for a <tt>java.util.List</tt>. Underlying
* collection is an <tt>ArrayList</tt>.
*
* @see java.util.ArrayList
* @author Gavin King
*/
public class PersistentList extends AbstractPersistentCollection implements List {
protected List list;
public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
EntityMode entityMode = getSession().getEntityMode();
ArrayList clonedList = new ArrayList( list.size() );
Iterator iter = list.iterator();
while ( iter.hasNext() ) {
Object deepCopy = persister.getElementType()
.deepCopy( iter.next(), entityMode, persister.getFactory() );
clonedList.add( deepCopy );
}
return clonedList;
}
public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
List sn = (List) snapshot;
return getOrphans( sn, list, entityName, getSession() );
}
public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
Type elementType = persister.getElementType();
List sn = (List) getSnapshot();
if ( sn.size()!=this.list.size() ) return false;
Iterator iter = list.iterator();
Iterator sniter = sn.iterator();
while ( iter.hasNext() ) {
if ( elementType.isDirty( iter.next(), sniter.next(), getSession() ) ) return false;
}
return true;
}
public boolean isSnapshotEmpty(Serializable snapshot) {
return ( (Collection) snapshot ).isEmpty();
}
public PersistentList(SessionImplementor session) {
super(session);
}
public PersistentList(SessionImplementor session, List list) {
super(session);
this.list = list;
setInitialized();
setDirectlyAccessible(true);
}
public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
this.list = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
}
public boolean isWrapper(Object collection) {
return list==collection;
}
public PersistentList() {} //needed for SOAP libraries, etc
/**
* @see java.util.List#size()
*/
public int size() {
return readSize() ? getCachedSize() : list.size();
}
/**
* @see java.util.List#isEmpty()
*/
public boolean isEmpty() {
return readSize() ? getCachedSize()==0 : list.isEmpty();
}
/**
* @see java.util.List#contains(Object)
*/
public boolean contains(Object object) {
Boolean exists = readElementExistence(object);
return exists==null ?
list.contains(object) :
exists.booleanValue();
}
/**
* @see java.util.List#iterator()
*/
public Iterator iterator() {
read();
return new IteratorProxy( list.iterator() );
}
/**
* @see java.util.List#toArray()
*/
public Object[] toArray() {
read();
return list.toArray();
}
/**
* @see java.util.List#toArray(Object[])
*/
public Object[] toArray(Object[] array) {
read();
return list.toArray(array);
}
/**
* @see java.util.List#add(Object)
*/
public boolean add(Object object) {
if ( !isOperationQueueEnabled() ) {
write();
return list.add(object);
}
else {
queueOperation( new SimpleAdd(object) );
return true;
}
}
/**
* @see java.util.List#remove(Object)
*/
public boolean remove(Object value) {
Boolean exists = isPutQueueEnabled() ? readElementExistence(value) : null;
if ( exists == null ) {
initialize( true );
if ( list.remove( value ) ) {
dirty();
return true;
}
else {
return false;
}
}
else if ( exists.booleanValue() ) {
queueOperation( new SimpleRemove(value) );
return true;
}
else {
return false;
}
}
/**
* @see java.util.List#containsAll(Collection)
*/
public boolean containsAll(Collection coll) {
read();
return list.containsAll(coll);
}
/**
* @see java.util.List#addAll(Collection)
*/
public boolean addAll(Collection values) {
if ( values.size()==0 ) {
return false;
}
if ( !isOperationQueueEnabled() ) {
write();
return list.addAll(values);
}
else {
Iterator iter = values.iterator();
while ( iter.hasNext() ) {
queueOperation( new SimpleAdd( iter.next() ) );
}
return values.size()>0;
}
}
/**
* @see java.util.List#addAll(int, Collection)
*/
public boolean addAll(int index, Collection coll) {
if ( coll.size()>0 ) {
write();
return list.addAll(index, coll);
}
else {
return false;
}
}
/**
* @see java.util.List#removeAll(Collection)
*/
public boolean removeAll(Collection coll) {
if ( coll.size()>0 ) {
initialize( true );
if ( list.removeAll( coll ) ) {
dirty();
return true;
}
else {
return false;
}
}
else {
return false;
}
}
/**
* @see java.util.List#retainAll(Collection)
*/
public boolean retainAll(Collection coll) {
initialize( true );
if ( list.retainAll( coll ) ) {
dirty();
return true;
}
else {
return false;
}
}
/**
* @see java.util.List#clear()
*/
public void clear() {
if ( isClearQueueEnabled() ) {
queueOperation( new Clear() );
}
else {
initialize( true );
if ( ! list.isEmpty() ) {
list.clear();
dirty();
}
}
}
/**
* @see java.util.List#get(int)
*/
public Object get(int index) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
Object result = readElementByIndex( new Integer(index) );
return result==UNKNOWN ? list.get(index) : result;
}
/**
* @see java.util.List#set(int, Object)
*/
public Object set(int index, Object value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
Object old = isPutQueueEnabled() ? readElementByIndex( new Integer(index) ) : UNKNOWN;
if ( old==UNKNOWN ) {
write();
return list.set(index, value);
}
else {
queueOperation( new Set(index, value, old) );
return old;
}
}
/**
* @see java.util.List#add(int, Object)
*/
public void add(int index, Object value) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
if ( !isOperationQueueEnabled() ) {
write();
list.add(index, value);
}
else {
queueOperation( new Add(index, value) );
}
}
/**
* @see java.util.List#remove(int)
*/
public Object remove(int index) {
if (index<0) {
throw new ArrayIndexOutOfBoundsException("negative index");
}
Object old = isPutQueueEnabled() ?
readElementByIndex( new Integer(index) ) : UNKNOWN;
if ( old==UNKNOWN ) {
write();
return list.remove(index);
}
else {
queueOperation( new Remove(index, old) );
return old;
}
}
/**
* @see java.util.List#indexOf(Object)
*/
public int indexOf(Object value) {
read();
return list.indexOf(value);
}
/**
* @see java.util.List#lastIndexOf(Object)
*/
public int lastIndexOf(Object value) {
read();
return list.lastIndexOf(value);
}
/**
* @see java.util.List#listIterator()
*/
public ListIterator listIterator() {
read();
return new ListIteratorProxy( list.listIterator() );
}
/**
* @see java.util.List#listIterator(int)
*/
public ListIterator listIterator(int index) {
read();
return new ListIteratorProxy( list.listIterator(index) );
}
/**
* @see java.util.List#subList(int, int)
*/
public java.util.List subList(int from, int to) {
read();
return new ListProxy( list.subList(from, to) );
}
public boolean empty() {
return list.isEmpty();
}
public String toString() {
read();
return list.toString();
}
public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
throws HibernateException, SQLException {
Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
int index = ( (Integer) persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() ) ).intValue();
//pad with nulls from the current last element up to the new index
for ( int i = list.size(); i<=index; i++) {
list.add(i, null);
}
list.set(index, element);
return element;
}
public Iterator entries(CollectionPersister persister) {
return list.iterator();
}
public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
throws HibernateException {
Serializable[] array = ( Serializable[] ) disassembled;
int size = array.length;
beforeInitialize( persister, size );
for ( int i = 0; i < size; i++ ) {
list.add( persister.getElementType().assemble( array[i], getSession(), owner ) );
}
}
public Serializable disassemble(CollectionPersister persister)
throws HibernateException {
int length = list.size();
Serializable[] result = new Serializable[length];
for ( int i=0; i<length; i++ ) {
result[i] = persister.getElementType().disassemble( list.get(i), getSession(), null );
}
return result;
}
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
List deletes = new ArrayList();
List sn = (List) getSnapshot();
int end;
if ( sn.size() > list.size() ) {
for ( int i=list.size(); i<sn.size(); i++ ) {
deletes.add( indexIsFormula ? sn.get(i) : new Integer(i) );
}
end = list.size();
}
else {
end = sn.size();
}
for ( int i=0; i<end; i++ ) {
if ( list.get(i)==null && sn.get(i)!=null ) {
deletes.add( indexIsFormula ? sn.get(i) : new Integer(i) );
}
}
return deletes.iterator();
}
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final List sn = (List) getSnapshot();
return list.get(i)!=null && ( i >= sn.size() || sn.get(i)==null );
}
public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException {
final List sn = (List) getSnapshot();
return i<sn.size() && sn.get(i)!=null && list.get(i)!=null &&
elemType.isDirty( list.get(i), sn.get(i), getSession() );
}
public Object getIndex(Object entry, int i, CollectionPersister persister) {
return new Integer(i);
}
public Object getElement(Object entry) {
return entry;
}
public Object getSnapshotElement(Object entry, int i) {
final List sn = (List) getSnapshot();
return sn.get(i);
}
public boolean equals(Object other) {
read();
return list.equals(other);
}
public int hashCode() {
read();
return list.hashCode();
}
public boolean entryExists(Object entry, int i) {
return entry!=null;
}
final class Clear implements DelayedOperation {
public void operate() {
list.clear();
}
public Object getAddedInstance() {
return null;
}
public Object getOrphan() {
throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
}
}
final class SimpleAdd implements DelayedOperation {
private Object value;
public SimpleAdd(Object value) {
this.value = value;
}
public void operate() {
list.add(value);
}
public Object getAddedInstance() {
return value;
}
public Object getOrphan() {
return null;
}
}
final class Add implements DelayedOperation {
private int index;
private Object value;
public Add(int index, Object value) {
this.index = index;
this.value = value;
}
public void operate() {
list.add(index, value);
}
public Object getAddedInstance() {
return value;
}
public Object getOrphan() {
return null;
}
}
final class Set implements DelayedOperation {
private int index;
private Object value;
private Object old;
public Set(int index, Object value, Object old) {
this.index = index;
this.value = value;
this.old = old;
}
public void operate() {
list.set(index, value);
}
public Object getAddedInstance() {
return value;
}
public Object getOrphan() {
return old;
}
}
final class Remove implements DelayedOperation {
private int index;
private Object old;
public Remove(int index, Object old) {
this.index = index;
this.old = old;
}
public void operate() {
list.remove(index);
}
public Object getAddedInstance() {
return null;
}
public Object getOrphan() {
return old;
}
}
final class SimpleRemove implements DelayedOperation {
private Object value;
public SimpleRemove(Object value) {
this.value = value;
}
public void operate() {
list.remove(value);
}
public Object getAddedInstance() {
return null;
}
public Object getOrphan() {
return value;
}
}
}
|