Author: jm
Date: 2012-09-18 12:05:12 -0700 (Tue, 18 Sep 2012)
New Revision: 30377

Added:
   
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyListImpl.java
Modified:
   
core3/api/trunk/model-api/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
   
core3/impl/trunk/io-impl/impl/src/main/java/org/cytoscape/io/internal/read/xgmml/handler/ReadDataManager.java
   
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
   
core3/impl/trunk/model-impl/impl/src/test/java/org/cytoscape/model/CyTableTest.java
Log:
Fixes #1426: Added wrapper for lists so it's cheap to get and update them while 
removing side effects

Modified: 
core3/api/trunk/model-api/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
===================================================================
--- 
core3/api/trunk/model-api/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
        2012-09-18 17:56:27 UTC (rev 30376)
+++ 
core3/api/trunk/model-api/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
        2012-09-18 19:05:12 UTC (rev 30377)
@@ -58,6 +58,13 @@
        protected boolean rowCreatedMicroListenerWasCalled;
        protected boolean rowAboutToBeDeletedMicroListenerWasCalled;
 
+       protected void assertListEquals(List<?> expected, List<?> actual) {
+               assertEquals(expected.size(), actual.size());
+               for (int i = 0; i < expected.size(); i++) {
+                       assertEquals(expected.get(i), actual.get(i));
+               }
+       }
+
        @Test
        public void testAddStringAttr() {
                table.createColumn("someString", String.class, false);
@@ -435,7 +442,7 @@
                final List<String> strings = new ArrayList<String>();
                strings.add("joe");
                attrs.set("l", strings);
-               assertEquals(attrs.getList("l", String.class), strings);
+               assertListEquals(attrs.getList("l", String.class), strings);
        }
 
        @Test(expected=NullPointerException.class)

Modified: 
core3/impl/trunk/io-impl/impl/src/main/java/org/cytoscape/io/internal/read/xgmml/handler/ReadDataManager.java
===================================================================
--- 
core3/impl/trunk/io-impl/impl/src/main/java/org/cytoscape/io/internal/read/xgmml/handler/ReadDataManager.java
       2012-09-18 17:56:27 UTC (rev 30376)
+++ 
core3/impl/trunk/io-impl/impl/src/main/java/org/cytoscape/io/internal/read/xgmml/handler/ReadDataManager.java
       2012-09-18 19:05:12 UTC (rev 30377)
@@ -517,8 +517,8 @@
                                        extEdgeIds = 
nphRow.getList(EXTERNAL_EDGE_ATTRIBUTE, Long.class);
                                                        
                                        if (extEdgeIds == null) {
-                                               extEdgeIds = new 
ArrayList<Long>();
-                                               
nphRow.set(EXTERNAL_EDGE_ATTRIBUTE, extEdgeIds);
+                                               
nphRow.set(EXTERNAL_EDGE_ATTRIBUTE, new ArrayList<Long>());
+                                               extEdgeIds = 
nphRow.getList(EXTERNAL_EDGE_ATTRIBUTE, Long.class);
                                        }
                                }
                        }

Added: 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyListImpl.java
===================================================================
--- 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyListImpl.java
                         (rev 0)
+++ 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyListImpl.java
 2012-09-18 19:05:12 UTC (rev 30377)
@@ -0,0 +1,263 @@
+package org.cytoscape.model.internal;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.cytoscape.event.CyEventHelper;
+import org.cytoscape.model.CyColumn;
+import org.cytoscape.model.CyRow;
+import org.cytoscape.model.events.RowSetRecord;
+import org.cytoscape.model.events.RowsSetEvent;
+
+public class CyListImpl<T> implements List<T> {
+       private Class<T> elementType;
+       private List<T> delegate;
+       private CyEventHelper eventHelper;
+       private CyRow row;
+       private CyColumn column;
+       
+       public CyListImpl(Class<T> elementType, List<T> delegate, CyEventHelper 
eventHelper, CyRow row, CyColumn column) {
+               this.elementType = elementType;
+               this.delegate = delegate;
+               this.eventHelper = eventHelper;
+               this.row = row;
+               this.column = column;
+       }
+       
+       public Class<T> getListElementType() {
+               return elementType;
+       }
+       
+       @Override
+       public boolean add(T item) {
+               checkType(item);
+               if (delegate.add(item)) {
+                       fireEvent();
+                       return true;
+               }
+               return false;
+       }
+
+       private void checkType(T item) {
+               if (item == null || 
!elementType.isAssignableFrom(item.getClass())) {
+                       throw new IllegalArgumentException("This list only 
allows objects of type " + elementType.getName());
+               }
+       }
+
+       private void fireEvent() {
+               // TODO: If this is a virtual column, we need to ensure all 
dependents
+               // fire events.
+               eventHelper.addEventPayload(row.getTable(), new 
RowSetRecord(row, column.getName(), this, this), RowsSetEvent.class);
+       }
+
+       @Override
+       public void add(int index, T item) {
+               checkType(item);
+               fireEvent();
+               delegate.add(index, item);
+       }
+
+       @Override
+       public boolean addAll(Collection<? extends T> items) {
+               for (T item : items) {
+                       checkType(item);
+               }
+               if (delegate.addAll(items)) {
+                       fireEvent();
+                       return true;
+               }
+               return false;
+       }
+
+       @Override
+       public boolean addAll(int index, Collection<? extends T> items) {
+               for (T item : items) {
+                       checkType(item);
+               }
+               if (delegate.addAll(index, items)) {
+                       fireEvent();
+                       return true;
+               }
+               return false;
+       }
+
+       @Override
+       public void clear() {
+               if (delegate.size() == 0) {
+                       return;
+               }
+               delegate.clear();
+               fireEvent(); 
+       }
+
+       @Override
+       public boolean contains(Object item) {
+               return delegate.contains(item);
+       }
+
+       @Override
+       public boolean containsAll(Collection<?> items) {
+               return delegate.containsAll(items);
+       }
+
+       @Override
+       public T get(int index) {
+               return delegate.get(index);
+       }
+
+       @Override
+       public int indexOf(Object item) {
+               return delegate.indexOf(item);
+       }
+
+       @Override
+       public boolean isEmpty() {
+               return delegate.isEmpty();
+       }
+
+       @Override
+       public Iterator<T> iterator() {
+               return listIterator();
+       }
+
+       @Override
+       public int lastIndexOf(Object item) {
+               return delegate.lastIndexOf(item);
+       }
+
+       @Override
+       public ListIterator<T> listIterator() {
+               final ListIterator<T> iterator = delegate.listIterator();
+               return createListIterator(iterator);
+       }
+
+       private ListIterator<T> createListIterator(final ListIterator<T> 
iterator) {
+               return new ListIterator<T>() {
+                       @Override
+                       public void add(T item) {
+                               checkType(item);
+                               iterator.add(item);
+                               fireEvent();
+                       }
+
+                       @Override
+                       public boolean hasNext() {
+                               return iterator.hasNext();
+                       }
+
+                       @Override
+                       public boolean hasPrevious() {
+                               return iterator.hasPrevious();
+                       }
+
+                       @Override
+                       public T next() {
+                               return iterator.next();
+                       }
+
+                       @Override
+                       public int nextIndex() {
+                               return iterator.nextIndex();
+                       }
+
+                       @Override
+                       public T previous() {
+                               return iterator.previous();
+                       }
+
+                       @Override
+                       public int previousIndex() {
+                               return iterator.previousIndex();
+                       }
+
+                       @Override
+                       public void remove() {
+                               iterator.remove();
+                               fireEvent();
+                       }
+
+                       @Override
+                       public void set(T item) {
+                               checkType(item);
+                               iterator.set(item);
+                               fireEvent();
+                       }
+               };
+       }
+
+       @Override
+       public ListIterator<T> listIterator(int index) {
+               return delegate.listIterator(index);
+       }
+
+       @Override
+       public boolean remove(Object item) {
+               if (delegate.remove(item)) {
+                       fireEvent();
+                       return true;
+               }
+               return false;
+       }
+
+       @Override
+       public T remove(int index) {
+               T value = delegate.remove(index);
+               if (value == null) {
+                       return null;
+               }
+               fireEvent();
+               return value;
+       }
+
+       @Override
+       public boolean removeAll(Collection<?> items) {
+               if (delegate.removeAll(items)) {
+                       fireEvent();
+                       return true;
+               }
+               return false;
+       }
+
+       @Override
+       public boolean retainAll(Collection<?> items) {
+               if (delegate.retainAll(items)) {
+                       fireEvent();
+                       return true;
+               }
+               return true;
+       }
+
+       @Override
+       public T set(int index, T item) {
+               T value = delegate.set(index, item);
+               fireEvent();
+               return value;
+       }
+
+       @Override
+       public int size() {
+               return delegate.size();
+       }
+
+       @Override
+       public List<T> subList(int fromIndex, int toIndex) {
+               return new CyListImpl<T>(elementType, 
delegate.subList(fromIndex, toIndex), eventHelper, row, column);
+       }
+
+       @Override
+       public Object[] toArray() {
+               return delegate.toArray();
+       }
+
+       @Override
+       public <S> S[] toArray(S[] container) {
+               return (S[]) delegate.toArray(container);
+       }
+       
+       @Override
+       public String toString() {
+               return delegate.toString();
+       }
+}

Modified: 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
===================================================================
--- 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
        2012-09-18 17:56:27 UTC (rev 30376)
+++ 
core3/impl/trunk/model-impl/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
        2012-09-18 19:05:12 UTC (rev 30377)
@@ -55,14 +55,13 @@
 import org.cytoscape.model.events.TableAddedListener;
 import org.cytoscape.model.events.TablePrivacyChangedEvent;
 import org.cytoscape.model.events.TableTitleChangedEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.HashMultimap;
 import com.google.common.collect.SetMultimap;
-import com.google.common.collect.HashMultimap;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-
 public final class CyTableImpl implements CyTable, TableAddedListener {
        
        private static final Logger logger = 
LoggerFactory.getLogger(CyTableImpl.class);
@@ -671,54 +670,63 @@
 
        private void setListX(final Object key, final String columnName, final 
Object value) {
                Object newValue;
-
+               final Object rawValue;
+               
+               
                synchronized(this) {
                        final String normalizedColName = 
normalizeColumnName(columnName);
+                       final CyColumn column = types.get(normalizedColName);
+                       CyRow row = rows.get(key);
+                       final Class<?> type = column.getListElementType();
                        
-                       if (value instanceof List) {
+                       if (value instanceof CyListImpl) {
+                               rawValue = value;
+                       } else if (value instanceof List) {
                                final List list = (List)value;
                                if (!list.isEmpty())
                                        checkType(list.get(0));
+                               rawValue = new CyListImpl(type, new 
ArrayList(list), eventHelper, row, column);
                        } else if (!(value instanceof Equation)) {
                                throw new IllegalArgumentException("value is a 
" + value.getClass().getName()
                                                                   + " and not 
a List for column '"
                                                                   + columnName 
+ "'.");
-                       } else if 
(!EqnSupport.listEquationIsCompatible((Equation)value,
-                                                 
types.get(normalizedColName).getListElementType())) {
+                       } else if 
(!EqnSupport.listEquationIsCompatible((Equation)value, type)) {
                                throw new IllegalArgumentException(
                                                                   "value is 
not a List equation of a compatible type for column '"
                                                                   + columnName 
+ "'.");
+                       } else {
+                               rawValue = value;
                        }
 
                        final VirtualColumn virtColumn = 
virtualColumnMap.get(normalizedColName);
                        
                        if (virtColumn != null) {
-                               virtColumn.setValue(key, value);
+                               virtColumn.setValue(key, rawValue);
                        }
-                       if (virtColumn != null && !(value instanceof Equation)) 
{
+                       if (virtColumn != null && !(rawValue instanceof 
Equation)) {
                                newValue = virtColumn.getListValue(key);
                        } else {
                                Map<Object, Object> keyToValueMap = 
attributes.get(normalizedColName);
 
                                // TODO this is an implicit addRow - not sure 
if we want to refactor this or not
                                final Object oldValue = keyToValueMap.get(key);
-                               keyToValueMap.put(key, value);
-                               if (value instanceof Equation) {
+                               keyToValueMap.put(key, rawValue);
+                               if (rawValue instanceof Equation) {
                                        final StringBuilder errorMsg = new 
StringBuilder();
-                                       newValue = 
EqnSupport.evalEquation((Equation)value, suid, interpreter,
+                                       newValue = 
EqnSupport.evalEquation((Equation)rawValue, suid, interpreter,
                                                                           
currentlyActiveAttributes, columnName,
                                                                           
errorMsg, this);
                                        lastInternalError = errorMsg.toString();
                                } else {
-                                       newValue = value;
-                                       addToReverseMap(columnName, key, 
oldValue, value);
+                                       newValue = rawValue;
+                                       addToReverseMap(columnName, key, 
oldValue, rawValue);
                                }
                        }
                }
 
                if (fireEvents)
                        eventHelper.addEventPayload((CyTable)this,
-                                                   new 
RowSetRecord(getRow(key),columnName,newValue, value),
+                                                   new 
RowSetRecord(getRow(key),columnName,newValue, rawValue),
                                                    RowsSetEvent.class);
        }
 

Modified: 
core3/impl/trunk/model-impl/impl/src/test/java/org/cytoscape/model/CyTableTest.java
===================================================================
--- 
core3/impl/trunk/model-impl/impl/src/test/java/org/cytoscape/model/CyTableTest.java
 2012-09-18 17:56:27 UTC (rev 30376)
+++ 
core3/impl/trunk/model-impl/impl/src/test/java/org/cytoscape/model/CyTableTest.java
 2012-09-18 19:05:12 UTC (rev 30377)
@@ -125,7 +125,7 @@
                attrs.set("booleanList", new BooleanList());
                final BooleanList nonEmptyList = new BooleanList(true, false);
                attrs.set("booleanList", nonEmptyList);
-               assertEquals(attrs.getList("booleanList", Boolean.class), 
nonEmptyList);
+               assertListEquals(attrs.getList("booleanList", Boolean.class), 
nonEmptyList);
        }
 
        //@Test : TODO: We removed support for strongly typed lists so this 
test is

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to