package er.extensions.eof; import java.lang.ref.WeakReference; import java.util.Enumeration; import java.util.Iterator; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOEnterpriseObject; import com.webobjects.eocontrol.EOGlobalID; import com.webobjects.foundation.NSArray; /** * Array that converts EOGlobalIDs to faults on the fly. The idea is that you can use this in * place of an array of real EOs, which may consume quite a lot of memory when instantiated in an EC. * May or may not only work without the Wonder version of NSArray. * @author ak * * @param <T> */ public class ERXFaultArray<T extends EOEnterpriseObject> extends NSArray<T> { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private EOEditingContext _editingContext; private EOGlobalID[] _array; private WeakReference<T>[] _refs; public ERXFaultArray(NSArray<T> array) { _refs = new WeakReference[array.size()]; _array = new EOGlobalID[array.size()]; if(array.count() > 0) { setEditingContext(array.lastObject().editingContext()); int i = 0; for (T eo : array) { _refs[i] = new WeakReference<>(eo); _array[i] = editingContext().globalIDForObject(eo); i++; } } } public ERXFaultArray(EOEditingContext ec, NSArray<EOGlobalID> array) { setEditingContext(ec); _refs = new WeakReference[array.size()]; _array = new EOGlobalID[array.size()]; int i = 0; for (EOGlobalID gid : array) { _refs[i] = null; _array[i] = gid; i++; } } @Override public T objectAtIndex(int index) { int count = count(); if (index >= 0 && index < count) { T result = null; WeakReference<T> ref = _refs[index]; if(ref != null) { result = ref.get(); } if(result == null) { EOGlobalID gid = _array[index]; result = (T)editingContext().objectForGlobalID(gid); if(result == null) { result = (T)editingContext().faultForGlobalID(gid, editingContext()); // System.out.println("fault: " + result.isFault()); } else { // System.out.println("object: " + result.isFault()); } _refs[index] = new WeakReference<>(result); } else { // System.out.println("no fault"); } return result; } if (count == 0) { throw new IllegalArgumentException("Array is empty"); } throw new IllegalArgumentException("Index (" + index + ") out of bounds [0, " + (count() - 1) + "]"); } @Override public boolean containsObject(Object object) { if (object instanceof EOEnterpriseObject) { EOEnterpriseObject eo = (EOEnterpriseObject) object; EOGlobalID gid = editingContext().globalIDForObject(eo); for (int i = 0; i < count(); i++) { EOGlobalID current = _array[i]; if(current.equals(gid)) { return true; } } return false; } return super.containsObject(object); } @Override public int indexOfObject(Object object) { if (object instanceof EOEnterpriseObject) { EOEnterpriseObject eo = (EOEnterpriseObject) object; EOGlobalID gid = editingContext().globalIDForObject(eo); for (int i = 0; i < count(); i++) { EOGlobalID current = _array[i]; if(current.equals(gid)) { return i; } } return NotFound; } return super.indexOfObject(object); } @Override public int count() { return _array != null ? _array.length : 0; } @Override public Iterator<T> iterator() { return new Iterator<T>() { int index = 0; public boolean hasNext() { return index < count(); } public T next() { return objectAtIndex(index++); } public void remove() { throw new UnsupportedOperationException(); } }; } @Override public Enumeration objectEnumerator() { return new Enumeration<T>() { int index = 0; public boolean hasMoreElements() { return index < count(); } public T nextElement() { return objectAtIndex(index++); } }; } @Override public Enumeration<T> reverseObjectEnumerator() { return new Enumeration<T>() { int index = count(); public boolean hasMoreElements() { return index > 0; } public T nextElement() { return objectAtIndex(--index); } }; } @Override protected Object[] _objects() { Object[] result = new Object[count()]; for (int i = 0; i < count(); i++) { result[i] = objectAtIndex(i); } return result; } public EOEditingContext editingContext() { return _editingContext; } @Override public Object clone() { ERXFaultArray other = new ERXFaultArray(_editingContext, NSArray.EmptyArray); other._array = _array; return other; } public void setEditingContext(EOEditingContext ec) { if(_editingContext != ec) { for (int i = 0; i < count(); i++) { _refs[i] = null; } } _editingContext = ec; } }