/* * Rapid Beans Framework: ReadonlyListCollection.java * * Copyright (C) 2009 Martin Bluemel * * Creation Date: 03/31/2006 * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * You should have received a copies of the GNU Lesser General Public License and the * GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>. */ package org.rapidbeans.core.common; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.rapidbeans.core.basic.BeanSorter; import org.rapidbeans.core.basic.PropertyCollection; import org.rapidbeans.core.exception.ImmutableCollectionException; import org.rapidbeans.core.type.TypeProperty; /** * Encapsulates any collection to make it 1) immutable (read only). Hence if you * try to use a changing method like add you get a RuntimeException 2) a List. * If the collection is a List the reading List methods use the List directly. * 3) If the collection is not a List the reading List methods work on an array * (internally made out of it) * * @author Martin Bluemel */ public class ReadonlyListCollection<T> implements List<T> { /** * the encapsulated collection. */ private Collection<T> collection; private TypeProperty proptype = null; /** * @return the collection */ protected Collection<T> getCollection() { return collection; } /** * setter. * * @param col * the new collection */ protected void setCollection(final Collection<T> col) { this.collection = col; } /** * @param col * the collection to encapsulate. */ public ReadonlyListCollection(final Collection<T> col, final TypeProperty propertyType) { this.proptype = propertyType; if (col instanceof ReadonlyListCollection) { this.collection = ((ReadonlyListCollection<T>) col).collection; } else { this.collection = col; } } /** * @return the size of the collection */ public int size() { return this.collection.size(); } /** * @return if the collection is empty */ public boolean isEmpty() { return this.collection.isEmpty(); } /** * @param o * the object to query * @return if the collection contains a given instance. */ public boolean contains(final Object o) { boolean contains; final TypeProperty[] propsbefore = BeanSorter.get(); try { PropertyCollection.prepareSorting(this.proptype); contains = this.collection.contains(o); } finally { PropertyCollection.cleanupSorting(this.proptype, propsbefore); } return contains; } /** * @return a read only form of the Iterator. */ public ReadonlyIteratorCollection<T> iterator() { return new ReadonlyIteratorCollection<T>(this.collection.iterator()); } /** * returns the collection converted to an array of Objects. Since an array * is immutable this is not a problem. * * @return the collection converted to an array of Objects */ public Object[] toArray() { Object[] array; final TypeProperty[] propsbefore = BeanSorter.get(); try { PropertyCollection.prepareSorting(this.proptype); array = this.collection.toArray(); } finally { PropertyCollection.cleanupSorting(this.proptype, propsbefore); } return array; } /** * returns the collection converted to a typed array. Since an array is * immutable this is not a problem. * * @param a * the pattern array * * @return the collection converted to an array * * @throws ArrayStoreException * in case the Object[] given has an incorrect type */ @SuppressWarnings("unchecked") public T[] toArray(final Object[] a) { T[] array; final TypeProperty[] propsbefore = BeanSorter.get(); try { PropertyCollection.prepareSorting(this.proptype); array = (T[]) this.collection.toArray(a); } finally { PropertyCollection.cleanupSorting(this.proptype, propsbefore); } return array; } /** * adding an object to an immutable collection is not allowed. * * @param o * the object to add * * @return no return this will throw a ImmutableCollectionException */ public boolean add(final Object o) { throw new ImmutableCollectionException(); } /** * removing an object of an immutable collection is not allowed. * * @param o * the object to remove * * @return no return this will throw a ImmutableCollectionException */ public boolean remove(final Object o) { throw new ImmutableCollectionException(); } /** * @param c * the collection to test against * * @return if this collection contains all instances of the given collection */ public boolean containsAll(final Collection<?> c) { boolean contains; final TypeProperty[] propsbefore = BeanSorter.get(); try { PropertyCollection.prepareSorting(this.proptype); contains = this.collection.containsAll(c); } finally { PropertyCollection.cleanupSorting(this.proptype, propsbefore); } return contains; } /** * adding an object to an immutable collection is not allowed. * * @param c * the collection with instances to add * @return no return this will throw a ImmutableCollectionException */ @SuppressWarnings("rawtypes") public boolean addAll(final Collection c) { throw new ImmutableCollectionException(); } /** * removing an instance from an immutable collection is not allowed. * * @param c * the collection with instances to remove * @return no return this will throw a ImmutableCollectionException */ public boolean removeAll(final Collection<?> c) { throw new ImmutableCollectionException(); } /** * removing an instance from an immutable collection is not allowed. * * @param c * the collection with instances not to remove * @return no return this will throw a ImmutableCollectionException */ public boolean retainAll(final Collection<?> c) { throw new ImmutableCollectionException(); } /** * removing an instance from an immutable collection is not allowed. */ public void clear() { throw new ImmutableCollectionException(); } /** * returns the element at the specified position in the list. Caution: * Collections that are no Lists will be converted to arrays which will * cause performance problems in case a big collections. * * @param index * the position * @return the element at the specified position in the list. */ @SuppressWarnings("unchecked") public T get(final int index) { if (this.collection instanceof List) { return ((List<T>) this.collection).get(index); } else { return (T) this.toArray()[index]; } } /** * returns the first index of the element with the given reference. * * @param o * the object reference tha specifies the element to search for * @return the last index of the element with the given reference or -1 if * not found */ public int indexOf(final Object o) { if (this.collection instanceof List) { return ((List<?>) this.collection).indexOf(o); } else { int i = 0; for (Object o1 : this.collection) { if (o1.equals(o)) { return i; } i++; } return -1; } } /** * returns the last index of the element with the given reference. * * @param o * the object reference that specifies the element to search for * @return the last index of the element with the given reference or -1 if * not found */ public int lastIndexOf(final Object o) { if (this.collection instanceof List) { return ((List<?>) this.collection).lastIndexOf(o); } else { Object[] oa = this.toArray(); for (int i = oa.length - 1; i >= 0; i--) { if (oa[i].equals(o)) { return i; } } return -1; } } /** * @return a list iterator starting at the begin of this list */ public ListIterator<T> listIterator() { if (this.collection instanceof List<?>) { return new ReadonlyIteratorCollection<T>(((List<T>) this.collection).listIterator()); } else { return new ReadonlyIteratorCollection<T>(new ArrayList<T>(this.collection).listIterator()); } } /** * @param index * the index to start iterating * * @return a list iterator starting at the given index */ public ListIterator<T> listIterator(final int index) { if (this.collection instanceof List<?>) { return new ReadonlyIteratorCollection<T>(((List<T>) this.collection).listIterator(index)); } else { return new ReadonlyIteratorCollection<T>(this.toArrayList().listIterator(index)); } } /** * @param fromIndex * the index of the first element to include * @param toIndex * the index of the last element to include * @return a list with part of the elements of this list */ public List<T> subList(final int fromIndex, final int toIndex) { if (this.collection instanceof List<?>) { return new ReadonlyListCollection<T>(((List<T>) this.collection).subList(fromIndex, toIndex), this.proptype); } else { return new ReadonlyListCollection<T>(this.toArrayList().subList(fromIndex, toIndex), this.proptype); } } /** * set an object of an immutable list is not allowed. * * @param index * the position where to set the element * @param element * the object to set * @return no return this will throw a ImmutableCollectionException */ public T set(final int index, final T element) { throw new ImmutableCollectionException(); } /** * adding an object to an immutable list is not allowed. * * @param index * the position where to add the element * @param element * the object to add */ public void add(final int index, final Object element) { throw new ImmutableCollectionException(); } /** * set an object of an immutable list is not allowed. * * @param index * the position where to add the elements * @param c * the collection with elements to add * @return no return this will throw a ImmutableCollectionException */ @SuppressWarnings("rawtypes") public boolean addAll(final int index, final Collection c) { throw new ImmutableCollectionException(); } /** * remove an object of an immutable list is not allowed. * * @param index * the position where to remove the element * @return no return this will throw a ImmutableCollectionException */ public T remove(final int index) { throw new ImmutableCollectionException(); } /** * implementation of equals method. * * @param o * the object to compare * * @return if the collection equals or not. */ public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Collection<?>)) { return false; } final Collection<?> col = (Collection<?>) o; if (this.size() != col.size()) { return false; } boolean equals = true; final Iterator<?> i1 = this.iterator(); final Iterator<?> i2 = col.iterator(); Object o1, o2; while (i1.hasNext()) { o1 = i1.next(); o2 = i2.next(); if (!o1.equals(o2)) { equals = false; break; } } return equals; } /** * implementation of hashCode(). * * @return the hash code. */ public int hashCode() { return super.hashCode(); } /** * checks for identity (same instance) with another collection. * * @param col * the collection to check * * @return if identical or not */ public boolean isSameCollection(final Collection<?> col) { return this.collection == col; } /** * returns the collection converted to an array list. Since an array list is * not immutable this method is private. * * @return the collection converted to an array */ private ArrayList<T> toArrayList() { return new ArrayList<T>(this.collection); } }