001: /* $Id: IntRowMap.java,v 1.5 2005/12/23 01:32:24 ahimanikya Exp $
002: * =======================================================================
003: * Copyright (c) 2005-2006 Axion Development Team. All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above
010: * copyright notice, this list of conditions and the following
011: * disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The names "Tigris", "Axion", nor the names of its contributors may
019: * not be used to endorse or promote products derived from this
020: * software without specific prior written permission.
021: *
022: * 4. Products derived from this software may not be called "Axion", nor
023: * may "Tigris" or "Axion" appear in their names without specific prior
024: * written permission.
025: *
026: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
027: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
028: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
029: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
030: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
031: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
033: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
034: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
035: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
036: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: * =======================================================================
038: */
039: package org.axiondb.engine.rowcollection;
040:
041: import java.util.ArrayList;
042: import java.util.List;
043: import java.util.NoSuchElementException;
044:
045: import org.axiondb.AxionException;
046: import org.axiondb.BindVariable;
047: import org.axiondb.Column;
048: import org.axiondb.ColumnIdentifier;
049: import org.axiondb.Function;
050: import org.axiondb.Index;
051: import org.axiondb.Literal;
052: import org.axiondb.Row;
053: import org.axiondb.RowCollection;
054: import org.axiondb.RowIterator;
055: import org.axiondb.Selectable;
056: import org.axiondb.Table;
057: import org.axiondb.engine.rowiterators.RebindableIndexedRowIterator;
058: import org.axiondb.engine.rowiterators.UnmodifiableRowIterator;
059: import org.axiondb.event.RowDeletedEvent;
060: import org.axiondb.event.RowEvent;
061: import org.axiondb.event.RowInsertedEvent;
062: import org.axiondb.event.RowUpdatedEvent;
063: import org.axiondb.functions.ComparisonFunction;
064:
065: /**
066: * Int key and Row value Map, this does not implement java.util.Map interface and has
067: * limited Map like API. Does not implement EntrySet and and KeySet, tather it just
068: * retunds their iterator.
069: *
070: * @version $Revision: 1.5 $ $Date: 2005/12/23 01:32:24 $
071: * @author Ahimanikya Satapathy
072: */
073:
074: public class IntRowMap extends IntHashMap {
075:
076: /** Creates an IntRowMap of small initial capacity. */
077: public IntRowMap() {
078: super (16);
079: }
080:
081: /**
082: * Creates an IntRowMap of specified initial capacity. Unless the map size exceeds the
083: * specified capacity no memory allocation is ever performed.
084: *
085: * @param capacity the initial capacity.
086: */
087: public IntRowMap(int capacity) {
088: super (capacity);
089: }
090:
091: /**
092: * Creates a IntRowMap containing the specified entries, in the order they are
093: * returned by the map's iterator.
094: *
095: * @param map the map whose entries are to be placed into this map.
096: */
097: public IntRowMap(IntRowMap map) {
098: super (map);
099: }
100:
101: public final void addIndex(Index index) {
102: _indices.add(index);
103: }
104:
105: public Row addRow(Table table, Row row) throws AxionException {
106: RowEvent event = null;
107: for (int i = 0, I = _indices.size(); i < I; i++) {
108: Index index = (Index) (_indices.get(i));
109: if (event == null) {
110: event = new RowInsertedEvent(table, null, row);
111: }
112: index.rowInserted(event);
113: }
114: return putRow(row.getIdentifier(), row);
115: }
116:
117: /**
118: * Removes all mappings from this {@link IntRowMap}.
119: */
120: public void clear() {
121: super .clear();
122: try {
123: truncateIndices();
124: } catch (AxionException e) {
125: clearIndexes();
126: }
127: }
128:
129: public final void clearIndexes() {
130: _indices.clear();
131: }
132:
133: public Row deleteRow(Table table, Row deleted)
134: throws AxionException {
135: deleted = removeRow(deleted.getIdentifier());
136: if (deleted != null) {
137: RowEvent event = null;
138: for (int i = 0, I = _indices.size(); i < I; i++) {
139: Index index = (Index) (_indices.get(i));
140: if (event == null) {
141: event = new RowDeletedEvent(table, deleted, null);
142: }
143: index.rowDeleted(event);
144: }
145: }
146: return deleted;
147: }
148:
149: public RowIterator getIndexedRows(Table source, Selectable node,
150: boolean readOnly) throws AxionException {
151: if (readOnly) {
152: return UnmodifiableRowIterator.wrap(getIndexedRows(source,
153: node));
154: }
155: return getIndexedRows(source, node);
156: }
157:
158: public Index getIndexForColumn(Column column) {
159: for (int i = 0, I = _indices.size(); i < I; i++) {
160: Index index = (Index) (_indices.get(i));
161: if (column.equals(index.getIndexedColumn())) {
162: return index;
163: }
164: }
165: return null;
166: }
167:
168: /**
169: * Returns the value to which this {@link IntRowMap}maps the specified key.
170: *
171: * @param key the key whose associated value is to be returned.
172: * @return the value to which this map maps the specified key, or <code>null</code>
173: * if there is no mapping for the key.
174: */
175: public final Row getRow(int key) {
176: return (Row) super .get(key);
177: }
178:
179: public boolean isColumnIndexed(Column column) {
180: for (int i = 0, I = _indices.size(); i < I; i++) {
181: Index index = (Index) (_indices.get(i));
182: if (column.equals(index.getIndexedColumn())) {
183: return true;
184: }
185: }
186: return false;
187: }
188:
189: public void populateIndex(Table table, Index index)
190: throws AxionException {
191: for (RowIterator i = rowValues().rowIterator(); i.hasNext();) {
192: Row row = i.next();
193: if (row != null) {
194: index
195: .rowInserted(new RowInsertedEvent(table, null,
196: row));
197: }
198: }
199: }
200:
201: /**
202: * Associates the specified value with the specified key in this {@link IntRowMap}.
203: * If the {@link IntRowMap}previously contained a mapping for this key, the old value
204: * is replaced.
205: *
206: * @param key the key with which the specified value is to be associated.
207: * @param value the value to be associated with the specified key.
208: * @return the previous value associated with specified key, or <code>null</code> if
209: * there was no mapping for key. A <code>null</code> return can also
210: * indicate that the map previously associated <code>null</code> with the
211: * specified key.
212: */
213: public final Row putRow(int key, Row value) {
214: return (Row) super .put(key, value);
215: }
216:
217: /**
218: * Removes the mapping for this key from this {@link IntRowMap}if present.
219: *
220: * @param key the key whose mapping is to be removed from the map.
221: * @return previous value associated with specified key, or <code>null</code> if
222: * there was no mapping for key. A <code>null</code> return can also
223: * indicate that the map previously associated <code>null</code> with the
224: * specified key.
225: */
226: public final Row removeRow(int key) {
227: return (Row) super .remove(key);
228: }
229:
230: /**
231: * Returns a list iterator over the values in this list in proper sequence, (this map
232: * maintains the insertion order).
233: *
234: * @return a list iterator of the values in this list (in proper sequence).
235: */
236: public final RowIterator rowIterator() {
237: return new ValueRowIterator();
238: }
239:
240: /**
241: * Returns a {@link RowCollection}view of the values contained in this
242: * {@link IntRowMap}. The collection is backed by the map, so changes to the map are
243: * reflected in the collection, and vice-versa. The collection supports element
244: * removal, which removes the corresponding mapping from this map, via the
245: * <code>RowIterator.remove</code>,<code>RowCollection.remove</code> and
246: * <code>clear</code> operations.
247: *
248: * @return a row collection view of the values contained in this map.
249: */
250: public final RowCollection rowValues() {
251: return _rowValues;
252: }
253:
254: public void shutdown() {
255: clear();
256: _indices = null;
257: }
258:
259: public void truncateIndices() throws AxionException {
260: for (int i = 0, I = _indices.size(); i < I; i++) {
261: Index index = (Index) (_indices.get(i));
262: index.truncate();
263: }
264: }
265:
266: public Row updateRow(Table table, Row oldrow, Row newrow)
267: throws AxionException {
268: newrow.setIdentifier(oldrow.getIdentifier());
269: oldrow = putRow(newrow.getIdentifier(), newrow);
270:
271: RowEvent event = null;
272: for (int i = 0, I = _indices.size(); i < I; i++) {
273: Index index = (Index) (_indices.get(i));
274: if (event == null) {
275: event = new RowUpdatedEvent(table, oldrow, newrow);
276: }
277: if (oldrow != null) {
278: index.rowUpdated(event);
279: } else {
280: index.rowInserted(event);
281: }
282: }
283: return oldrow;
284: }
285:
286: private RowIterator getIndexedRows(Table source, Selectable node)
287: throws AxionException {
288: if (node instanceof ComparisonFunction) {
289: // attempting to map comparison function to existing index
290: ComparisonFunction function = (ComparisonFunction) node;
291:
292: Column column = null;
293: Literal literal = null;
294: Selectable left = function.getArgument(0);
295: Selectable right = function.getArgument(1);
296: if (left instanceof ColumnIdentifier
297: && right instanceof Literal) {
298: column = source.getColumn(((ColumnIdentifier) left)
299: .getName());
300: literal = (Literal) (right);
301: } else if (left instanceof Literal
302: && right instanceof ColumnIdentifier) {
303: column = source.getColumn(((ColumnIdentifier) right)
304: .getName());
305: literal = (Literal) (left);
306: function = function.flip();
307: } else {
308: return null;
309: }
310:
311: if (!isColumnIndexed(column)) {
312: // no index for column
313: return null;
314: }
315:
316: Index index = getIndexForColumn(column);
317: if (!index.supportsFunction(function)) {
318: // index does not support required function
319: return null;
320: } else if (literal instanceof BindVariable) {
321: // index found
322: return new RebindableIndexedRowIterator(index, source,
323: function, (BindVariable) literal);
324: } else {
325: // index found
326: return index.getRowIterator(source, function, literal
327: .evaluate(null));
328: }
329: } else if (node instanceof ColumnIdentifier) {
330: Column column = source.getColumn(((ColumnIdentifier) node)
331: .getName());
332: Index index = getIndexForColumn(column);
333: if (index != null) {
334: return index.getInorderRowIterator(source);
335: }
336: } else if (node instanceof Function) { // IS NULL and IS NOT NULL
337: Function function = (Function) node;
338: if (function.getArgumentCount() != 1) {
339: return null;
340: }
341:
342: Selectable colid = function.getArgument(0);
343: if (colid instanceof ColumnIdentifier) {
344: Column column = source
345: .getColumn(((ColumnIdentifier) colid).getName());
346: if (!isColumnIndexed(column)) {
347: // no index for column
348: return null;
349: }
350:
351: Index index = getIndexForColumn(column);
352: if (!index.supportsFunction(function)) {
353: // index does not support required function
354: return null;
355: } else {
356: // index found
357: return index.getRowIterator(source, function, null);
358: }
359: }
360: }
361:
362: return null; // No matching index found
363: }
364:
365: private final class RowValues extends Values implements
366: RowCollection {
367: public boolean add(Row row) {
368: addEntry(row.getIdentifier(), row.getIdentifier(), row);
369: return true;
370: }
371:
372: public boolean contains(Row row) {
373: return IntRowMap.this .containsValue(row);
374: }
375:
376: public boolean remove(Row row) {
377: return super .remove(row);
378: }
379:
380: public RowIterator rowIterator() {
381: return IntRowMap.this .rowIterator();
382: }
383: }
384:
385: private class ValueRowIterator extends EntryIterator implements
386: RowIterator {
387:
388: public void add(Row row) throws UnsupportedOperationException,
389: AxionException {
390: addEntry(row.getIdentifier(), row.getIdentifier(), row);
391: }
392:
393: public Row current() throws NoSuchElementException {
394: return (Row) currentEntry().getValue();
395: }
396:
397: public Row first() throws NoSuchElementException,
398: AxionException {
399: return (Row) firstEntry().getValue();
400: }
401:
402: public Row last() throws NoSuchElementException, AxionException {
403: return (Row) lastEntry().getValue();
404: }
405:
406: public Row next() throws NoSuchElementException, AxionException {
407: return (Row) nextEntry().getValue();
408: }
409:
410: public int next(int count) throws AxionException {
411: for (int i = 0; i < count; i++) {
412: next();
413: }
414: return current().getIdentifier();
415: }
416:
417: public Row peekNext() throws NoSuchElementException,
418: AxionException {
419: return (Row) peekNextEntry().getValue();
420: }
421:
422: public Row peekPrevious() throws NoSuchElementException,
423: AxionException {
424: return (Row) peekPreviousEntry().getValue();
425: }
426:
427: public Row previous() throws NoSuchElementException,
428: AxionException {
429: return (Row) previousEntry().getValue();
430: }
431:
432: public int previous(int count) throws AxionException {
433: for (int i = 0; i < count; i++) {
434: previous();
435: }
436: return current().getIdentifier();
437: }
438:
439: public void set(Row row) throws UnsupportedOperationException,
440: AxionException {
441: if (!hasCurrent()) {
442: throw new IllegalStateException();
443: }
444: currentEntry().setValue(row);
445: }
446:
447: }
448:
449: private transient List _indices = new ArrayList(4);
450:
451: /** Holds the values view. */
452: private transient RowValues _rowValues = new RowValues();
453: }
|