/* * Copyright (c) 2002,2008 Declarative Engineering LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Declarative Engineering LLC * verson 1 which accompanies this distribution, and is available at * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt */ package com.common.util; import java.util.Arrays; import com.common.comparison.Comparator; import com.common.comparison.IComparator; import com.common.event.*; import com.common.exception.*; /** * The LiteCollection base class provides collection functionality without any event handling or synchronization. * If you need event handling or synchronization you should use a collection class that extends Collection. */ public abstract class LiteCollection implements ICollection { private boolean isChangeable = true; /** * LiteCollection constructor. */ protected LiteCollection() { super(); }//LiteCollection()// /** * LiteCollection constructor. * @param isChangeable Whether the collection may be changed. This should be false if the collection may no longer be modified. */ protected LiteCollection(boolean isChangeable) { super(); this.isChangeable = isChangeable; }//LiteCollection()// /** * Ensures that the collection can hold at least the number of components specified by the minimum capacity argument. * @param minimumCapacity The desired minimum capacity of this collection (above what it currently holds). */ public abstract void ensureCapacity(int minimumCapacity); /* (non-Javadoc) * @see com.common.util.ICollection#add(java.lang.Object) */ public int add(Object value) { //Verify that the collection can be modified.// verifyIsChangeable(); return internalAdd(value); }//add()// /* (non-Javadoc) * @see com.common.util.ICollection#addAll(java.lang.Object[]) */ public boolean addAll(Object[] values) { return addAll(values, 0, values.length); }//addAll()// /* (non-Javadoc) * @see com.common.util.ICollection#addAll(java.lang.Object[], int, int) */ public boolean addAll(Object[] values, int offset, int length) { boolean result = true; //Verify that the collection can be modified.// verifyIsChangeable(); //Resize the collection only once if it requires it at all.// ensureCapacity(length); //Make sure that the collection has values.// if((values != null) && (values.length > 0) && (length + offset <= values.length) && (offset >= 0)) { Object next = null; //Iterate over the items to be added and add them one at a time.// for(int index = offset; index < length; index++) { next = values[index]; if(internalAdd(next) == -1) { result = false; }//if// }//while// }//if// else { result = false; }//else// return result; }//addAll()// /* (non-Javadoc) * @see com.common.util.ICollection#addAll(com.common.util.ICollection) */ public boolean addAll(ICollection values) { boolean result = true; if(values instanceof IIndexedCollection) { result = addAll((IIndexedCollection) values, 0, values.getSize()); }//if// else { //Verify that the collection can be modified.// verifyIsChangeable(); //Resize the collection only once if it requires it at all.// ensureCapacity(values.getSize()); //Make sure that the collection has values.// if((values != null) && (values.getSize() > 0)) { Object next = null; //Iterate over the items to be added and add them one at a time.// for(IIterator iterator = values.iterator(); iterator.hasNext(); ) { next = iterator.next(); if(internalAdd(next) == -1) { result = false; }//if// }//for// }//if// else { result = false; }//else// }//else// return result; }//addAll()// /* (non-Javadoc) * @see com.common.util.ICollection#addAll(com.common.util.IIndexedCollection, int, int) */ public boolean addAll(IIndexedCollection values, int offset, int length) { boolean result = true; //Verify that the collection can be modified.// verifyIsChangeable(); //Resize the collection only once if it requires it at all.// ensureCapacity(length); //Make sure that the collection has values.// if((values != null) && (length > 0)) { Object next = null; //Iterate over the items to be added and add them one at a time.// for(int valuesIndex = offset, count = offset + length; valuesIndex < count; valuesIndex++) { next = values.get(valuesIndex); if(internalAdd(next) == -1) { result = false; }//if// }//for// }//if// else { result = false; }//else// return result; }//addAll()// /* (non-Javadoc) * @see com.common.util.ICollection#addAll(com.common.util.IIterator) */ public boolean addAll(IIterator values) { boolean result = true; //Verify that the collection can be modified.// verifyIsChangeable(); //Make sure that the collection has values.// if(values != null) { Object next = null; //Iterate over the items to be added and add them one at a time.// while(values.hasNext()) { next = values.next(); if(internalAdd(next) == -1) { result = false; }//if// }//for// }//if// else { result = false; }//else// return result; }//addAll()// /* (non-Javadoc) * @see com.common.util.ICollection#collect(com.common.event.ObjectHandler1, com.common.util.IList) */ public IList collect(ObjectHandler1 handler, IList results) { IIterator iterator = iterator(); if(results == null) { results = new LiteList(getSize()); }//if// //Iterate over the items in this collection passing them to the handler, and collect the resulting values.// while(iterator.hasNext()) { results.add(handler.evaluate(iterator.next())); }//while// return results; }//collect()// /* (non-Javadoc) * @see com.common.util.ICollection#containsValue(java.lang.Object) */ public abstract boolean containsValue(Object value); /* (non-Javadoc) * @see com.common.util.ICollection#getSize() */ public abstract int getSize(); /** * Will add a value to the collection. * @param value Object The value to add. * @return The index of the addition if the collection is indexed, 0 if the collection is not indexed, or -1 if the operation failed. */ protected abstract int internalAdd(Object value); /** * Will remove a value from the collection. * @param value Object The value to remove. * @return boolean Will return true if the operation was successful. */ protected abstract boolean internalRemove(Object value); /** * Will remove all of the values in the collection. * @return boolean Will return true if the operation was successful. */ protected abstract void internalRemoveAll(); /** * Replaces one value with another in the collection. * @param oldValue Object The value to replace. * @param newValue Object The value to insert. * @return boolean Will return true if the operation was successful. */ protected abstract boolean internalReplace(Object oldValue, Object newValue); /** * Replaces the values currently in the collection with the given collection of values. * @param values The values to replace the ones currently in the collection. * @return Returns true if the operation was successful. */ protected abstract boolean internalReplaceAll(ICollection values); /** * Replaces the removed values in the current collection with those in the added values collection. * @param removedValues The values to be replaced. * @param addedValues The values to replace the removed values. Note that the collections need not be of the same size. * @return Whether the operation completed successfully. The operation may only partially complete if this is false. */ protected abstract boolean internalReplaceAll(ICollection removedValues, ICollection addedValues); /* (non-Javadoc) * @see com.common.util.ICollection#isChangeable() */ public boolean isChangeable() { return isChangeable; }//isChangeable()// /* (non-Javadoc) * @see com.common.util.ICollection#isChangeable(boolean) */ public void isChangeable(boolean isChangeable) { if(!isChangeable) { this.isChangeable = isChangeable; }//if// else if(this.isChangeable == isChangeable) { //Do nothing as nothing has changed.// }//else if// else { throw new RuntimeException("You may not change the collection to be changeable after it has been locked."); }//else// }//isChangeable()// /* (non-Javadoc) * @see com.common.util.ICollection#iterator() */ public abstract IIterator iterator(); /* (non-Javadoc) * @see com.common.util.ICollection#perform(com.common.event.VoidHandler1) */ public void perform(VoidHandler1 handler) { IIterator iterator = iterator(); //Iterate over the items in this collection passing them to the handler to perform some function.// while(iterator.hasNext()) { handler.evaluate(iterator.next()); }//while// }//perform()// /** * Will read the collection from the stream. * @param in java.io.ObjectInput The stream that the object data can be read from. */ public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException { }//readExternal()// /* (non-Javadoc) * @see com.common.util.ICollection#reject(com.common.event.BooleanHandler1, com.common.util.IList) */ public IList reject(BooleanHandler1 handler, IList results) { IIterator iterator = iterator(); if(results == null) { results = new LiteList(10, 50); }//if// //Iterate over the items in this collection passing them to the handler, and collect the resulting values.// while(iterator.hasNext()) { Object value = iterator.next(); if(!handler.evaluate(value).booleanValue()) { results.add(value); }//if// }//while// return results; }//reject()// /* (non-Javadoc) * @see com.common.util.ICollection#remove(java.lang.Object) */ public boolean remove(Object value) { //Verify that the collection can be modified.// verifyIsChangeable(); return internalRemove(value); }//remove()// /* (non-Javadoc) * @see com.common.util.ICollection#removeAll() */ public void removeAll() { //Verify that the collection can be modified.// verifyIsChangeable(); internalRemoveAll(); }//removeAll()// /* (non-Javadoc) * @see com.common.util.ICollection#removeAll(java.lang.Object[]) */ public boolean removeAll(Object[] values) { return removeAll(values, 0, values.length); }//removeAll()// /* (non-Javadoc) * @see com.common.util.ICollection#removeAll(java.lang.Object[], int, int) */ public boolean removeAll(Object[] values, int offset, int length) { boolean result = true; //Verify that this collection can be modified.// verifyIsChangeable(); //Make sure that there are values to remove.// if((values != null) && (values.length > 0) && (offset >= 0) && (offset + length <= values.length)) { Object next = null; //Remove the values one at a time.// for(int index = offset; index < length; index++) { next = values[index]; if(!internalRemove(next)) { result = false; }//if// }//while// }//if// else { result = false; }//else// return result; }//removeAll()// /* (non-Javadoc) * @see com.common.util.ICollection#removeAll(com.common.util.ICollection) */ public boolean removeAll(ICollection values) { boolean result = true; //Verify that this collection can be modified.// verifyIsChangeable(); //Make sure that there are values to remove.// if((values != null) && (values.getSize() > 0)) { Object next = null; //Remove the values one at a time.// for(IIterator iterator = values.iterator(); iterator.hasNext(); ) { next = iterator.next(); if(!internalRemove(next)) { result = false; }//if// }//for// }//if// else { result = false; }//else// return result; }//removeAll()// /* (non-Javadoc) * @see com.common.util.ICollection#removeAll(com.common.util.ICollection) */ public boolean removeAll(IIterator values) { boolean result = true; //Verify that this collection can be modified.// verifyIsChangeable(); //Make sure that there are values to remove.// if(values != null) { Object next = null; //Remove the values one at a time.// while(values.hasNext()) { next = values.next(); if(!internalRemove(next)) { result = false; }//if// }//for// }//if// else { result = false; }//else// return result; }//removeAll()// /* (non-Javadoc) * @see com.common.util.ICollection#replace(java.lang.Object, java.lang.Object) */ public boolean replace(Object oldValue, Object newValue) { //Verify that this collection can be modified.// verifyIsChangeable(); return internalReplace(oldValue, newValue); } //replace()// /* (non-Javadoc) * @see com.common.util.ICollection#replaceAll(com.common.util.ICollection) */ public boolean replaceAll(ICollection values) { return internalReplaceAll(values); }//replaceAll()// /* (non-Javadoc) * @see com.common.util.ICollection#replaceAll(com.common.util.ICollection, com.common.util.ICollection) */ public boolean replaceAll(ICollection removedValues, ICollection addedValues) { return internalReplaceAll(removedValues, addedValues); }//replaceAll()// /* (non-Javadoc) * @see com.common.util.ICollection#select(com.common.event.BooleanHandler1, com.common.util.IList) */ public IList select(BooleanHandler1 handler, IList results) { IIterator iterator = iterator(); if(results == null) { results = new LiteList(10, 50); }//if// //Iterate over the items in this collection passing them to the handler, and collect the resulting values.// while(iterator.hasNext()) { Object value = iterator.next(); if(handler.evaluate(value).booleanValue()) { results.add(value); }//if// }//while// return results; }//select()// /** * Converts the list to an object array. * @return Object[] An array of the values in the collection. */ public Object[] toArray() { Object[] result = new Object[getSize()]; toArray(result); return result; }//toArray()// /* (Non-Javadoc) * @see ICollection.toArray(Object) */ public abstract int toArray(Object array); /** * Verifies that the collection may be modified. * @throws IllegalOperationException If the isImmutable flag is set. */ protected void verifyIsChangeable() { if(!isChangeable) { throw new IllegalOperationException("The collection is immutable which prevents the collection from being modified."); }//if// }//verifyIsChangeable()// /** * Writes the collection to the stream. * @param out java.io.ObjectOutput The stream that the object data can be written to. */ public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException { }//writeExternal()// /** * Calculates the diffences between the old array and new array. * @param oldArray The old array. * @param newArray The new array. * @param comparator The optional comparator used to determine equality. If null then exact equality will be used (==). * @param added The optional set of items that are new in the new array (that don't exist in the old array). * @param removed The optional set of items that are old in the old array (that don't exist in the new array). * @param unchanged The optional set of items that have not changed and are in both arrays. */ public static void calculateDifferences(Object[] oldArray, Object[] newArray, IComparator comparator, ICollection added, ICollection removed, ICollection unchanged) { boolean[] newMatched = new boolean[newArray.length]; Arrays.fill(newMatched, false); if(comparator == null) { comparator = Comparator.getIdentityComparator(); }//if// //For each old item, see if it exists in the new items and add to the appropriate collections. Mark matched items so we can easily see which items are new.// for(int oldIndex = 0; oldIndex < oldArray.length; oldIndex++) { boolean found = false; //Search for a match in the new collection.// for(int newIndex = 0; (!found) && (newIndex < newArray.length); newIndex++) { if((!newMatched[newIndex]) && (Comparator.isEqual(comparator.compare(oldArray[oldIndex], newArray[newIndex])))) { found = true; newMatched[newIndex] = true; if(unchanged != null) { unchanged.add(oldArray[oldIndex]); }//if// }//if// }//for// if((!found) && (removed != null)) { removed.add(oldArray[oldIndex]); }//if// }//for// //If we need to collect added items then iterate over the new items and add those that are not marked as matched.// if(added != null) { for(int newIndex = 0; newIndex < newArray.length; newIndex++) { if(!newMatched[newIndex]) { added.add(newArray[newIndex]); }//if// }//for// }//if// }//calculateDifferences()// }//LiteCollection//