Author: ruschein
Date: 2011-01-21 10:03:21 -0800 (Fri, 21 Jan 2011)
New Revision: 23538

Modified:
   core3/model-api/trunk/src/main/java/org/cytoscape/model/CyTable.java
   
core3/model-api/trunk/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
   
core3/model-impl/trunk/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
   
core3/model-impl/trunk/impl/src/test/java/org/cytoscape/model/CyTableTest.java
Log:
Added virtual table columns.

Modified: core3/model-api/trunk/src/main/java/org/cytoscape/model/CyTable.java
===================================================================
--- core3/model-api/trunk/src/main/java/org/cytoscape/model/CyTable.java        
2011-01-21 17:05:14 UTC (rev 23537)
+++ core3/model-api/trunk/src/main/java/org/cytoscape/model/CyTable.java        
2011-01-21 18:03:21 UTC (rev 23538)
@@ -162,4 +162,27 @@
         *  @return The number if rows in the table.
         */
        int getRowCount();
+
+       /** Adds a "virtual" column to the the current table.
+        *  @param virtualColumn  the name of the new virtual column
+        *  @param sourceColumn   the name of the column in "sourceTable" that 
will be mapped to
+        *                        "virtualColumn"
+        *  @param sourceTable    the table that really contains the column 
that we're adding (all
+        *                        updates and lookups of this new column will 
be redirected to here)
+        *  @param sourceJoinKey  the column in "sourceTable" that will be used 
for the join
+        *  @param targetJoinKey  the column in current table that will be used 
for the join
+        *  Note: The types of "sourceJoinKey" and "targetJoinKey" have to be 
identical.
+        */
+       void addVirtualColumn(String virtualColumn, String sourceColumn, 
CyTable sourceTable,
+                             String sourceJoinKey, String targetJoinKey);
+
+       /** Adds all columns in another table as "virtual" columns to the the 
current table.
+        *  @param sourceTable    the table that really contains the column 
that we're adding (all
+        *                        updates and lookups of this new column will 
be redirected to here)
+        *  @param sourceJoinKey  the column in "sourceTable" that will be used 
for the join
+        *  @param targetJoinKey  the column in current table that will be used 
for the join
+        *  Note: The types of "sourceJoinKey" and "targetJoinKey" have to be 
identical.  Also none
+        *        of the column names in "sourceTable" must exist in the 
current table!
+        */
+       void addVirtualColumns(CyTable sourceTable, String sourceJoinKey, 
String targetJoinKey);
 }

Modified: 
core3/model-api/trunk/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
===================================================================
--- 
core3/model-api/trunk/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
    2011-01-21 17:05:14 UTC (rev 23537)
+++ 
core3/model-api/trunk/src/test/java/org/cytoscape/model/AbstractCyTableTest.java
    2011-01-21 18:03:21 UTC (rev 23538)
@@ -47,6 +47,7 @@
 
 public abstract class AbstractCyTableTest {
        protected CyTable table;
+       protected CyTable table2;
        protected CyRow attrs;
        protected DummyCyEventHelper eventHelper; 
        protected boolean rowSetMicroListenerWasCalled;
@@ -554,4 +555,96 @@
                final CyRow row = table.getRow(107L);
                assertEquals(row.get(table.getPrimaryKey(), 
table.getPrimaryKeyType()), 107L);
        }
+
+       @Test
+       public void testVirtualColumnType() {
+               table.createColumn("x", Long.class);
+               table2.createColumn("x2", Long.class);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               assertEquals("Virtual column type should have been String!",
+                            String.class, table.getType("s1"));
+       }
+
+       @Test
+       public void testVirtualColumnIsSet() {
+               table.createColumn("x", Integer.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               assertFalse(row1.isSet("s1", String.class));
+               row2.set("s", "abc");
+               assertTrue(row1.isSet("s1", String.class));
+       }
+
+       @Test
+       public void testVirtualColumnGet() {
+               table.createColumn("x", Integer.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               assertFalse(row1.isSet("s1", String.class));
+               row2.set("s", "abc");
+               assertEquals(row1.get("s1", String.class), "abc");
+       }
+
+       @Test
+       public void testVirtualColumnSetWithAReplacementValue() {
+               table.createColumn("x", Integer.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               assertFalse(row1.isSet("s1", String.class));
+               row2.set("s", "abc");
+               assertEquals(row1.get("s1", String.class), "abc");
+               row1.set("s1", "xyz");
+               assertEquals(row1.get("s1", String.class), "xyz");
+       }
+
+       @Test
+       public void testVirtualColumnUnset() {
+               table.createColumn("x", Integer.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               row2.set("s", "abc");
+               assertTrue(row1.isSet("s1", String.class));
+               row1.set("s1", null);
+               assertFalse(row1.isSet("s1", String.class));
+       }
+
+       @Test
+       public void testVirtualColumnGetMatchingRows() {
+               table.createColumn("x", Integer.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               assertFalse(row1.isSet("s1", String.class));
+               row2.set("s", "abc");
+               Set<CyRow> matchingRows = table.getMatchingRows("s1", "abc");
+               assertEquals(matchingRows.size(), 1);
+               CyRow matchingRow = matchingRows.iterator().next();
+               assertEquals(matchingRow.get("s1", String.class), "abc");
+               assertEquals(matchingRow.get("x", Integer.class), 
Integer.valueOf(33));
+       }
 }

Modified: 
core3/model-impl/trunk/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
===================================================================
--- 
core3/model-impl/trunk/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
     2011-01-21 17:05:14 UTC (rev 23537)
+++ 
core3/model-impl/trunk/impl/src/main/java/org/cytoscape/model/internal/CyTableImpl.java
     2011-01-21 18:03:21 UTC (rev 23538)
@@ -54,7 +54,91 @@
 
 
 public final class CyTableImpl implements CyTable {
-       private static int counter = 0;
+       private final class VirtualColumn {
+               private final CyTable sourceTable;
+               private final String sourceColumn;
+               private final Class<?> sourceColumnType;
+               private final Class<?> sourceColumnListElementType;
+               private final CyTableImpl targetTable;
+               private final String sourceJoinColumn;
+               private final Class<?> sourceJoinColumnType;
+               private final String targetJoinColumn;
+
+               VirtualColumn(final CyTable sourceTable, final String 
sourceColumn,
+                             final CyTableImpl targetTable, final String 
sourceJoinColumn,
+                             final String targetJoinColumn)
+               {
+                       this.sourceTable                 = sourceTable;
+                       this.sourceColumn                = sourceColumn;
+                       this.sourceColumnType            = 
sourceTable.getType(sourceColumn);
+                       this.sourceColumnListElementType = (sourceColumnType == 
List.class)
+                               ? sourceTable.getListElementType(sourceColumn) 
: null;
+                       this.targetTable                 = targetTable;
+                       this.sourceJoinColumn            = sourceJoinColumn;
+                       this.sourceJoinColumnType        = 
sourceTable.getType(sourceJoinColumn);
+                       this.targetJoinColumn            = targetJoinColumn;
+               }
+
+               Object getRawValue(final Object targetKey) {
+                       final CyRow sourceRow = getSourceRow(targetKey);
+                       return (sourceRow == null) ? null : 
sourceRow.getRaw(sourceColumn);
+               }
+
+               void setValue(final Object targetKey, final Object value) {
+                       final CyRow sourceRow = getSourceRow(targetKey);
+                       if (sourceRow == null)
+                               throw new IllegalArgumentException("can't set a 
value for a virtual column!");
+                       sourceRow.set(sourceColumn, value);
+               }
+
+               Object getValue(final Object targetKey) {
+                       final CyRow sourceRow = getSourceRow(targetKey);
+                       if (sourceRow == null)
+                               return null;
+                       final Object retValue = sourceRow.get(sourceColumn, 
sourceColumnType);
+                       if (retValue == null)
+                               targetTable.lastInternalError = 
sourceTable.getLastInternalError();
+                       return retValue;
+               }
+
+               Object getListValue(final Object targetKey) {
+                       final CyRow sourceRow = getSourceRow(targetKey);
+                       if (sourceRow == null)
+                               return null;
+                       final Object retValue = sourceRow.getList(sourceColumn, 
sourceColumnListElementType);
+                       if (retValue == null)
+                               targetTable.lastInternalError = 
sourceTable.getLastInternalError();
+                       return retValue;
+               }
+
+               private CyRow getSourceRow(final Object targetKey) {
+                       final Object joinKey = targetTable.getValue(targetKey, 
targetJoinColumn);
+                       if (joinKey == null)
+                               return null;
+                       final Set<CyRow> sourceRows = 
sourceTable.getMatchingRows(sourceJoinColumn,
+                                                                               
  joinKey);
+                       if (sourceRows.size() != 1)
+                               return null;
+
+                       return sourceRows.iterator().next();
+               }
+
+               Set<CyRow> getMatchingRows(final Object value) {
+                       final Set<CyRow> sourceRows = 
sourceTable.getMatchingRows(sourceColumn, value);
+                       final Set<CyRow> targetRows = new HashSet<CyRow>();
+                       for (final CyRow sourceRow : sourceRows) {
+                               final Object targetValue = 
sourceRow.get(sourceJoinColumn,
+                                                                        
sourceJoinColumnType);
+                               if (targetValue != null) {
+                                       final Set<CyRow> rows =
+                                               
targetTable.getMatchingRows(targetJoinColumn, targetValue);
+                                       targetRows.addAll(rows);
+                               }
+                       }
+                       return targetRows;
+               }
+       }
+
        private static final Logger logger = 
LoggerFactory.getLogger(CyTableImpl.class);
 
        private final Set<String> currentlyActiveAttributes;
@@ -85,6 +169,8 @@
 
        private String lastInternalError = null;
 
+       private final Map<String, VirtualColumn> virtualColumnMap;
+
        /**
         * Creates a new CyTableImpl object.
         *
@@ -119,6 +205,8 @@
                types.put(primaryKey, primaryKeyType);
                attributes.put(primaryKey, new HashMap<Object, Object>());
                reverse.put(primaryKey, new HashMap<Object, Set<Object>>());
+
+               virtualColumnMap = new HashMap<String, VirtualColumn>();
        }
 
        /**
@@ -349,6 +437,10 @@
 
        @Override
        synchronized public Set<CyRow> getMatchingRows(final String columnName, 
final Object value) {
+               final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+               if (virtColumn != null)
+                       return virtColumn.getMatchingRows(value);
+
                final Map<Object, Set<Object>> valueToKeysMap = 
reverse.get(columnName);
 
                final Set<Object> keys = valueToKeysMap.get(value);
@@ -363,21 +455,24 @@
        }
 
        private void setX(final Object key, final String columnName, final 
Object value) {
+               if (columnName == null)
+                       throw new NullPointerException("columnName must not be 
null!");
+               if (value == null)
+                       throw new NullPointerException("value must not be 
null!");
+
                Object newValue;
                Object newRawValue;
 
                synchronized(this) {
-                       ++counter;
-                       if (columnName == null)
-                               throw new NullPointerException("columnName must 
not be null!");
-                       if (value == null)
-                               throw new NullPointerException("value must not 
be null!");
-
                        final Class<?> columnType = types.get(columnName);
-                       if (columnType == null || 
!attributes.containsKey(columnName))
-                               throw new IllegalArgumentException("attribute: 
'" + columnName
-                                                                  + "' does 
not yet exist!");
 
+                       final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+                       if (virtColumn == null) {
+                               if (columnType == null || 
!attributes.containsKey(columnName))
+                                       throw new 
IllegalArgumentException("attribute: '" + columnName
+                                                                          + "' 
does not yet exist!");
+                       }
+
                        if (types.get(columnName) == List.class) {
                                setListX(key, columnName, value);
                                return;
@@ -386,34 +481,39 @@
                        if (!(value instanceof Equation))
                                checkType(value);
 
-                       Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
+                       if (virtColumn != null) {
+                               virtColumn.setValue(key, value);
+                               newValue = virtColumn.getValue(key);
+                               newRawValue = virtColumn.getRawValue(key);
+                       } else {
+                               Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
 
-                       final Class targetType = types.get(columnName);
-                       if (!targetType.isAssignableFrom(value.getClass())
-                           && !EqnSupport.scalarEquationIsCompatible(value, 
targetType))
-                               throw new IllegalArgumentException("value is 
not of type: "
-                                                                  + 
types.get(columnName));
+                               if 
(!columnType.isAssignableFrom(value.getClass())
+                                   && 
!EqnSupport.scalarEquationIsCompatible(value, columnType))
+                                       throw new 
IllegalArgumentException("value is not of type: "
+                                                                          + 
columnType);
 
-                       if (value instanceof Equation) {
-                               newRawValue = value;
-                               final Equation equation = (Equation)value;
-                               // TODO this is an implicit addRow - not sure 
if we want to refactor this or not
-                               keyToValueMap.put(key, equation);
+                               if (value instanceof Equation) {
+                                       newRawValue = value;
+                                       final Equation equation = 
(Equation)value;
+                                       // TODO this is an implicit addRow - 
not sure if we want to refactor this or not
+                                       keyToValueMap.put(key, equation);
 
-                               final StringBuilder errorMsg = new 
StringBuilder();
-                               newValue = EqnSupport.evalEquation(equation, 
key, interpreter,
-                                                                  
currentlyActiveAttributes, columnName,
-                                                                  errorMsg, 
this);
-                               lastInternalError = errorMsg.toString();
-                               if (newValue == null)
-                                       logger.warn("attempted premature 
evaluation evaluation for "
-                                                   + equation);
-                       } else {
-                               // TODO this is an implicit addRow - not sure 
if we want to refactor this or not
-                               newRawValue = newValue = columnType.cast(value);
-                               final Object oldValue = keyToValueMap.get(key);
-                               keyToValueMap.put(key, newValue);
-                               addToReverseMap(columnName, key, oldValue, 
newValue);
+                                       final StringBuilder errorMsg = new 
StringBuilder();
+                                       newValue = 
EqnSupport.evalEquation(equation, key, interpreter,
+                                                                          
currentlyActiveAttributes, columnName,
+                                                                          
errorMsg, this);
+                                       lastInternalError = errorMsg.toString();
+                                       if (newValue == null)
+                                               logger.warn("attempted 
premature evaluation evaluation for "
+                                                           + equation);
+                               } else {
+                                       // TODO this is an implicit addRow - 
not sure if we want to refactor this or not
+                                       newRawValue = newValue = 
columnType.cast(value);
+                                       final Object oldValue = 
keyToValueMap.get(key);
+                                       keyToValueMap.put(key, newValue);
+                                       addToReverseMap(columnName, key, 
oldValue, newValue);
+                               }
                        }
                }
 
@@ -464,20 +564,26 @@
                                                                   "value is 
not a List equation of a compatible type for column '"
                                                                   + columnName 
+ "'!");
 
-                       Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
+                       final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+                       if (virtColumn != null) {
+                               virtColumn.setValue(key, value);
+                               newValue = virtColumn.getListValue(key);
+                       } else {
+                               Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
 
-                       // 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) {
-                               final StringBuilder errorMsg = new 
StringBuilder();
-                               newValue = 
EqnSupport.evalEquation((Equation)value, suid, interpreter,
-                                                                  
currentlyActiveAttributes, columnName,
-                                                                  errorMsg, 
this);
-                               lastInternalError = errorMsg.toString();
-                       } else {
-                               newValue = value;
-                               addToReverseMap(columnName, key, oldValue, 
value);
+                               // 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) {
+                                       final StringBuilder errorMsg = new 
StringBuilder();
+                                       newValue = 
EqnSupport.evalEquation((Equation)value, suid, interpreter,
+                                                                          
currentlyActiveAttributes, columnName,
+                                                                          
errorMsg, this);
+                                       lastInternalError = errorMsg.toString();
+                               } else {
+                                       newValue = value;
+                                       addToReverseMap(columnName, key, 
oldValue, value);
+                               }
                        }
                }
 
@@ -487,18 +593,23 @@
 
        synchronized private void unSetX(final Object key, final String 
columnName) {
                synchronized(this) {
-                       if (!types.containsKey(columnName) || 
!attributes.containsKey(columnName))
-                               throw new IllegalArgumentException("attribute: 
'" + columnName
-                                                                  + "' does 
not yet exist!");
+                       final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+                       if (virtColumn != null)
+                               virtColumn.setValue(key, null);
+                       else {
+                               if (!types.containsKey(columnName) || 
!attributes.containsKey(columnName))
+                                       throw new 
IllegalArgumentException("attribute: '" + columnName
+                                                                          + "' 
does not yet exist!");
 
-                       final Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
-                       if (!keyToValueMap.containsKey(key))
-                               return;
+                               final Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
+                               if (!keyToValueMap.containsKey(key))
+                                       return;
 
-                       final Object value = keyToValueMap.get(key);
-                       if (!(value instanceof Equation))
-                               removeFromReverseMap(columnName, key, value);
-                       keyToValueMap.remove(key);
+                               final Object value = keyToValueMap.get(key);
+                               if (!(value instanceof Equation))
+                                       removeFromReverseMap(columnName, key, 
value);
+                               keyToValueMap.remove(key);
+                       }
                }
 
                eventHelper.getMicroListener(RowSetMicroListener.class,
@@ -529,6 +640,10 @@
                        throw new IllegalArgumentException("use getList() to 
retrieve lists!");
                lastInternalError = null;
 
+               final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+               if (virtColumn != null)
+                       return (T)virtColumn.getValue(key);
+
                final Object vl = getValueOrEquation(key, columnName);
                if (vl == null)
                        return null;
@@ -546,6 +661,10 @@
        }
 
        Object getValue(Object key, String columnName) {
+               final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+               if (virtColumn != null)
+                       return virtColumn.getValue(key);
+
                final Object vl = getValueOrEquation(key, columnName);
                if (vl == null)
                        return null;
@@ -576,6 +695,11 @@
                                                           + "!");
 
                lastInternalError = null;
+
+               final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+               if (virtColumn != null)
+                       return (List<?extends T>)virtColumn.getListValue(key);
+
                final Object vl = getValueOrEquation(key, columnName);
                if (vl == null)
                        return null;
@@ -595,16 +719,21 @@
        synchronized private <T> boolean isSetX(final Object key, final String 
columnName,
                                                final Class<? extends T> type)
        {
-               if (!attributes.containsKey(columnName))
-                       return false;
+               final VirtualColumn virtColumn = 
virtualColumnMap.get(columnName);
+               if (virtColumn != null)
+                       return virtColumn.getRawValue(key) != null;
+               else {
+                       if (!attributes.containsKey(columnName))
+                               return false;
 
-               if (!types.get(columnName).isAssignableFrom(type))
-                       throw new IllegalArgumentException("type mismatch: 
expected \""
-                                                          + 
types.get(columnName).getName()
-                                                          + "\" got \"" + 
type.getName() + "\"!");
+                       if (!types.get(columnName).isAssignableFrom(type))
+                               throw new IllegalArgumentException("type 
mismatch: expected \""
+                                                                  + 
types.get(columnName).getName()
+                                                                  + "\" got 
\"" + type.getName() + "\"!");
 
-               final Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
-               return keyToValueMap.get(key) != null;
+                       final Map<Object, Object> keyToValueMap = 
attributes.get(columnName);
+                       return keyToValueMap.get(key) != null;
+               }
        }
 
        private Class<?> getClass(Class<?> c) {
@@ -652,6 +781,81 @@
                        throw new RuntimeException("invalid type: " + 
o.getClass().toString());
        }
 
+       @Override
+       synchronized public final void addVirtualColumn(final String 
virtualColumn,
+                                                       final String 
sourceColumn,
+                                                       final CyTable 
sourceTable,
+                                                       final String 
sourceJoinKey,
+                                                       final String 
targetJoinKey)
+       {
+               if (virtualColumn == null)
+                       throw new NullPointerException("\"virtualColumn\" 
argument must never be null!");
+               if (sourceColumn == null)
+                       throw new NullPointerException("\"sourceColumn\" 
argument must never be null!");
+               if (sourceTable == null)
+                       throw new NullPointerException("\"sourceTable\" 
argument must never be null!");
+               if (sourceJoinKey == null)
+                       throw new NullPointerException("\"sourceJoinKey\" 
argument must never be null!");
+               if (targetJoinKey == null)
+                       throw new NullPointerException("\"targetJoinKey\" 
argument must never be null!");
+
+               if (types.containsKey(virtualColumn))
+                       throw new IllegalArgumentException("\"virtualColumn\" 
name already in use!");
+
+               final Class<?> sourceColumnType = 
sourceTable.getType(sourceColumn);
+               if (sourceColumnType == null)
+                       throw new IllegalArgumentException("\"sourceColumn\" is 
not a column in \"sourceColumn\"!");
+
+               final Class<?> sourceJoinKeyType = 
sourceTable.getType(sourceJoinKey);
+               if (sourceJoinKeyType == null)
+                       throw new IllegalArgumentException("\"sourceJoinKey\" 
is not a known column in \"sourceTable\"!");
+
+               final Class<?> targetJoinKeyType = this.getType(targetJoinKey);
+               if (targetJoinKeyType == null)
+                       throw new IllegalArgumentException("\"targetJoinKey\" 
is not a known column in this table!");
+
+               if (sourceJoinKeyType != targetJoinKeyType)
+                       throw new IllegalArgumentException("\"sourceJoinKey\" 
has a different type from \"targetJoinKey\"!");
+
+               types.put(virtualColumn, sourceColumnType);
+               virtualColumnMap.put(
+                       virtualColumn,
+                       new VirtualColumn(sourceTable, sourceColumn, this, 
sourceJoinKey, targetJoinKey));
+       }
+
+       @Override
+       synchronized public final void addVirtualColumns(final CyTable 
sourceTable,
+                                                        final String 
sourceJoinKey,
+                                                        final String 
targetJoinKey)
+       {
+               if (sourceTable == null)
+                       throw new NullPointerException("\"sourceTable\" 
argument must never be null!");
+               if (sourceJoinKey == null)
+                       throw new NullPointerException("\"sourceJoinKey\" 
argument must never be null!");
+               if (targetJoinKey == null)
+                       throw new NullPointerException("\"targetJoinKey\" 
argument must never be null!");
+
+               final Class<?> sourceJoinKeyType = 
sourceTable.getType(sourceJoinKey);
+               if (sourceJoinKeyType == null)
+                       throw new IllegalArgumentException("\"sourceJoinKey\" 
is not a known column in \"sourceTable\"!");
+
+               final Class<?> targetJoinKeyType = this.getType(targetJoinKey);
+               if (targetJoinKeyType == null)
+                       throw new IllegalArgumentException("\"targetJoinKey\" 
is not a known column in this table!");
+
+               if (sourceJoinKeyType != targetJoinKeyType)
+                       throw new IllegalArgumentException("\"sourceJoinKey\" 
has a different type from \"targetJoinKey\"!");
+
+               // Makes sure that none of the column names in "sourceTable" 
clash w/ names in this table:
+               final Map<String, Class<?>> nameToTypeMap = 
sourceTable.getColumnTypeMap();
+               for (final String column : nameToTypeMap.keySet()) {
+                       if (column.equals(sourceJoinKey))
+                               continue;
+
+                       addVirtualColumn(column, column, sourceTable, 
sourceJoinKey, targetJoinKey);
+               }
+       }
+
        private final class InternalRow implements CyRow {
                private final Object key;
                private final CyTable table;

Modified: 
core3/model-impl/trunk/impl/src/test/java/org/cytoscape/model/CyTableTest.java
===================================================================
--- 
core3/model-impl/trunk/impl/src/test/java/org/cytoscape/model/CyTableTest.java  
    2011-01-21 17:05:14 UTC (rev 23537)
+++ 
core3/model-impl/trunk/impl/src/test/java/org/cytoscape/model/CyTableTest.java  
    2011-01-21 18:03:21 UTC (rev 23538)
@@ -60,6 +60,7 @@
                final Interpreter interpreter = new InterpreterImpl();
                table = new CyTableImpl("homer", "SUID", Long.class, true, 
eventHelper, interpreter);
                attrs = table.getRow(1L);
+               table2 = new CyTableImpl("marge", "SUID", Long.class, true, 
eventHelper, interpreter);
        }
 
        @After
@@ -189,4 +190,25 @@
                attrs.set("a", compiler.getEquation());
                assertNotNull(table.getLastInternalError());
        }
+
+       @Test
+       public void testVirtualColumnWithAnEquationReference() {
+               table.createColumn("x", Integer.class);
+               table.createColumn("ss", String.class);
+               CyRow row1 = table.getRow(1L);
+               row1.set("x", 33);
+               table2.createColumn("x2", Integer.class);
+               CyRow row2 =  table2.getRow(1L);
+               row2.set("x2", 33);
+               table2.createColumn("s", String.class);
+               table.addVirtualColumn("s1", "s", table2, "x2", "x");
+               row2.set("s", "abc");
+
+               final Map<String, Class<?>> varnameToTypeMap = new 
HashMap<String, Class<?>>();
+               varnameToTypeMap.put("s1", String.class);
+               compiler.compile("=\"XXX\"&$s1", varnameToTypeMap);
+               row1.set("ss", compiler.getEquation());
+
+               assertEquals(row1.get("ss", String.class), "XXXabc");
+       }
 }

-- 
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