001: package prefuse.data.tuple;
002:
003: import java.util.Iterator;
004: import java.util.logging.Logger;
005:
006: import prefuse.data.Graph;
007: import prefuse.data.Table;
008: import prefuse.data.Tuple;
009: import prefuse.util.StringLib;
010: import prefuse.util.collections.IntIterator;
011:
012: /**
013: * Manager class for Tuples. There is a unique Tuple for each row of a table.
014: * All data structures and Tuples are created lazily, on an as-needed basis.
015: * When a row is deleted from the table, it's corresponding Tuple (if created)
016: * is invalidated before being removed from this data structure, ensuring that
017: * any other live references to the Tuple can't be used to corrupt the table.
018: *
019: * @author <a href="http://jheer.org">jeffrey heer</a>
020: */
021: public class TupleManager {
022:
023: protected Graph m_graph;
024: protected Table m_table;
025: protected Class m_tupleType;
026:
027: private TableTuple[] m_tuples;
028:
029: /**
030: * Create a new TupleManager for the given Table.
031: * @param t the data Table to generate Tuples for
032: */
033: public TupleManager(Table t, Graph g, Class tupleType) {
034: init(t, g, tupleType);
035: }
036:
037: /**
038: * Initialize this TupleManager for use with a given Table.
039: * @param t the data Table to generate Tuples for
040: */
041: public void init(Table t, Graph g, Class tupleType) {
042: if (m_table != null) {
043: throw new IllegalStateException(
044: "This TupleManager has already been initialized");
045: }
046: m_table = t;
047: m_graph = g;
048: m_tupleType = tupleType;
049: m_tuples = null;
050: }
051:
052: /**
053: * Get the type of Tuple instances to generate.
054: * @return the tuple type, as a Class instance
055: */
056: public Class getTupleType() {
057: return m_tupleType;
058: }
059:
060: /**
061: * Ensure the tuple array exists.
062: */
063: private void ensureTupleArray(int row) {
064: int nrows = Math.max(m_table.getRowCount(), row + 1);
065: if (m_tuples == null) {
066: m_tuples = new TableTuple[nrows];
067: } else if (m_tuples.length < nrows) {
068: int capacity = Math.max((3 * m_tuples.length) / 2 + 1,
069: nrows);
070: TableTuple[] tuples = new TableTuple[capacity];
071: System.arraycopy(m_tuples, 0, tuples, 0, m_tuples.length);
072: m_tuples = tuples;
073: }
074: }
075:
076: /**
077: * Get a Tuple corresponding to the given row index.
078: * @param row the row index
079: * @return the Tuple corresponding to the given row
080: */
081: public Tuple getTuple(int row) {
082: if (m_table.isValidRow(row)) {
083: ensureTupleArray(row);
084: if (m_tuples[row] == null) {
085: return (m_tuples[row] = newTuple(row));
086: } else {
087: return m_tuples[row];
088: }
089: } else {
090: // TODO: return null instead?
091: throw new IllegalArgumentException("Invalid row index: "
092: + row);
093: }
094: }
095:
096: /**
097: * Instantiate a new Tuple instance for the given row index.
098: * @param row the row index of the tuple
099: * @return the newly created Tuple
100: */
101: protected TableTuple newTuple(int row) {
102: try {
103: TableTuple t = (TableTuple) m_tupleType.newInstance();
104: t.init(m_table, m_graph, row);
105: return t;
106: } catch (Exception e) {
107: Logger.getLogger(getClass().getName()).warning(
108: e.getMessage() + "\n" + StringLib.getStackTrace(e));
109: return null;
110: }
111: }
112:
113: /**
114: * Invalidate the tuple at the given row.
115: * @param row the row index to invalidate
116: */
117: public void invalidate(int row) {
118: if (m_tuples == null || row < 0 || row >= m_tuples.length) {
119: return;
120: } else if (m_tuples[row] != null) {
121: m_tuples[row].invalidate();
122: m_tuples[row] = null;
123: }
124: }
125:
126: /**
127: * Invalidate all tuples managed by this TupleManager
128: */
129: public void invalidateAll() {
130: if (m_tuples == null)
131: return;
132: for (int i = 0; i < m_tuples.length; ++i)
133: invalidate(i);
134: }
135:
136: /**
137: * Return an iterator over the tuples in this manager.
138: * @param rows an iterator over table rows
139: * @return an iterator over the tuples indicated by the input row iterator
140: */
141: public Iterator iterator(IntIterator rows) {
142: return new TupleManagerIterator(this , rows);
143: }
144:
145: // ------------------------------------------------------------------------
146: // TupleManagerIterator
147:
148: /**
149: * Iterator instance for iterating over tuples managed in a TupleManager.
150: */
151: public class TupleManagerIterator implements Iterator {
152:
153: private TupleManager m_tuples;
154: private IntIterator m_rows;
155:
156: /**
157: * Create a new TupleManagerIterator.
158: * @param tuples the TupleManager from which to get the tuples
159: * @param rows the rows to iterate over
160: */
161: public TupleManagerIterator(TupleManager tuples,
162: IntIterator rows) {
163: m_tuples = tuples;
164: m_rows = rows;
165: }
166:
167: /**
168: * @see java.util.Iterator#hasNext()
169: */
170: public boolean hasNext() {
171: return m_rows.hasNext();
172: }
173:
174: /**
175: * @see java.util.Iterator#next()
176: */
177: public Object next() {
178: return m_tuples.getTuple(m_rows.nextInt());
179: }
180:
181: /**
182: * @see java.util.Iterator#remove()
183: */
184: public void remove() {
185: // TODO: check to see if this is safe
186: m_rows.remove();
187: }
188:
189: } // end of inner class TupleManagerIterator
190:
191: } // end of class TupleManager
|