summaryrefslogtreecommitdiff
path: root/java/src/Freeze/MapInternal/IteratorI.java
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2009-05-18 14:03:42 -0700
committerMark Spruiell <mes@zeroc.com>2009-05-18 14:03:42 -0700
commitb30ccc77d3a9822c6ffcebf9b45945822df200bc (patch)
tree94105ea42fa81ad0b8731b05a46c7f64304dec55 /java/src/Freeze/MapInternal/IteratorI.java
parentRemoved Freeze.UseNonmutating (diff)
downloadice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.tar.bz2
ice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.tar.xz
ice-b30ccc77d3a9822c6ffcebf9b45945822df200bc.zip
bug 252 - Freeze finalizers
bug 2552 - Update Freeze for Java5
Diffstat (limited to 'java/src/Freeze/MapInternal/IteratorI.java')
-rw-r--r--java/src/Freeze/MapInternal/IteratorI.java422
1 files changed, 422 insertions, 0 deletions
diff --git a/java/src/Freeze/MapInternal/IteratorI.java b/java/src/Freeze/MapInternal/IteratorI.java
new file mode 100644
index 00000000000..4af39cf7498
--- /dev/null
+++ b/java/src/Freeze/MapInternal/IteratorI.java
@@ -0,0 +1,422 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package Freeze.MapInternal;
+
+import Freeze.Connection;
+import Freeze.ConnectionI;
+import Freeze.DatabaseException;
+import Freeze.DeadlockException;
+import Freeze.NotFoundException;
+import Freeze.Map;
+
+class IteratorI<K, V> implements Freeze.Map.EntryIterator<java.util.Map.Entry<K, V>>
+{
+ IteratorI(MapI<K, V> map, IteratorModel<K, V> model)
+ {
+ _map = map;
+ _model = model;
+ _trace = model.traceLevels();
+ _dbName = model.dbName();
+
+ try
+ {
+ _txn = _map.connection().dbTxn();
+ _cursor = _model.openCursor();
+ }
+ catch(com.sleepycat.db.DeadlockException dx)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(
+ _trace.errorPrefix + "EntryIterator constructor: " + dx.getMessage(),
+ _map.connection().currentTransaction());
+ ex.initCause(dx);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException dx)
+ {
+ dead();
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(dx);
+ ex.message = _trace.errorPrefix + "EntryIterator constructor: " + dx.getMessage();
+ throw ex;
+ }
+
+ _iteratorListToken = _map.addIterator(this);
+ }
+
+ public boolean
+ hasNext()
+ {
+ if(_current == null || _current == _lastReturned)
+ {
+ try
+ {
+ if(_current == null)
+ {
+ _current = _model.firstEntry(_cursor);
+ }
+ else
+ {
+ _current = _model.nextEntry(_cursor);
+ }
+ }
+ catch(com.sleepycat.db.DeadlockException dx)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(
+ _trace.errorPrefix + "Dbc.get: " + dx.getMessage(), _map.connection().currentTransaction());
+ ex.initCause(dx);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException dx)
+ {
+ dead();
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(dx);
+ ex.message = _trace.errorPrefix + "Dbc.get: " + dx.getMessage();
+ throw ex;
+ }
+
+ //
+ // For a read-only iterator, we can close the cursor automatically when there
+ // are no more entries.
+ //
+ if(_current == null && _txn == null)
+ {
+ close();
+ }
+
+ if(_current != null)
+ {
+ _current.iterator(this);
+ }
+
+ return _current != null;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ public java.util.Map.Entry<K, V>
+ next()
+ {
+ if(hasNext())
+ {
+ _lastReturned = _current;
+ return _lastReturned;
+ }
+ else
+ {
+ throw new java.util.NoSuchElementException();
+ }
+ }
+
+ public void
+ remove()
+ {
+ if(_txn == null)
+ {
+ throw new UnsupportedOperationException(
+ _trace.errorPrefix + "Cannot remove using an iterator without a transaction");
+ }
+
+ //
+ // Remove the last object returned by next()
+ //
+ if(_lastReturned == null)
+ {
+ throw new IllegalStateException();
+ }
+
+ if(_lastReturned == _current)
+ {
+ try
+ {
+ if(_cursor.delete() == com.sleepycat.db.OperationStatus.KEYEMPTY)
+ {
+ throw new IllegalStateException();
+ }
+ }
+ catch(com.sleepycat.db.DeadlockException e)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(_trace.errorPrefix + "Dbc.del: " + e.getMessage(),
+ _map.connection().currentTransaction());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException e)
+ {
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(e);
+ ex.message = _trace.errorPrefix + "Dbc.del: " + e.getMessage();
+ throw ex;
+ }
+ }
+ else
+ {
+ //
+ // Duplicate the cursor and move the _lastReturned element to delete it (using the duplicate).
+ //
+
+ //
+ // This works only for non-index iterators.
+ //
+ if(_cursor instanceof com.sleepycat.db.SecondaryCursor)
+ {
+ throw new UnsupportedOperationException(
+ _trace.errorPrefix + "Cannot remove using an iterator retrieved through an index");
+ }
+
+ com.sleepycat.db.Cursor clone = null;
+
+ try
+ {
+ clone = _cursor.dup(true);
+
+ //
+ // Not interested in data.
+ //
+ com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry();
+ dbValue.setPartial(true);
+
+ com.sleepycat.db.OperationStatus rc = clone.getSearchKey(_lastReturned.getDbKey(), dbValue, null);
+
+ if(rc == com.sleepycat.db.OperationStatus.NOTFOUND)
+ {
+ throw new IllegalStateException();
+ }
+ if(clone.delete() == com.sleepycat.db.OperationStatus.KEYEMPTY)
+ {
+ throw new IllegalStateException();
+ }
+ }
+ catch(com.sleepycat.db.DeadlockException e)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(
+ _trace.errorPrefix + "EntryIterator.remove: " + e.getMessage(),
+ _map.connection().currentTransaction());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException e)
+ {
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(e);
+ ex.message = _trace.errorPrefix + "EntryIterator.remove: " + e.getMessage();
+ throw ex;
+ }
+ finally
+ {
+ if(clone != null)
+ {
+ closeCursor(clone);
+ }
+ }
+ }
+ }
+
+ //
+ // Extra operations.
+ //
+ public void
+ close()
+ {
+ if(_iteratorListToken != null)
+ {
+ _map.removeIterator(_iteratorListToken);
+ _iteratorListToken = null;
+ }
+
+ if(_cursor != null)
+ {
+ com.sleepycat.db.Cursor cursor = _cursor;
+ _cursor = null;
+ closeCursor(cursor);
+ }
+ }
+
+ //
+ // An alias for close()
+ //
+ public void
+ destroy()
+ {
+ close();
+ }
+
+ protected void
+ finalize()
+ throws Throwable
+ {
+ if(_cursor != null)
+ {
+ _trace.logger.warning(
+ "iterator leaked for Map \"" + _dbName + "\"; the application " +
+ "should have closed it earlier by calling Map.EntryIterator.close(), " +
+ "Map.closeAllIterators(), Map.close(), Connection.close(), or (if also " +
+ "leaking a transaction) Transaction.commit() or Transaction.rollback()");
+ }
+ super.finalize();
+ }
+
+ void
+ setValue(EntryI<K, V> entry, V value)
+ {
+ if(_cursor instanceof com.sleepycat.db.SecondaryCursor)
+ {
+ throw new UnsupportedOperationException(
+ _trace.errorPrefix + "Cannot set an iterator retrieved through an index");
+ }
+
+ if(_txn == null)
+ {
+ throw new UnsupportedOperationException(
+ _trace.errorPrefix + "Cannot set a value without a transaction");
+ }
+
+ //
+ // Are we trying to update the current value?
+ //
+ if(_current == entry)
+ {
+ //
+ // Yes, update it directly
+ //
+ byte[] v = _map.encodeValue(value, _map.connection().getCommunicator());
+ com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(v);
+
+ try
+ {
+ _cursor.putCurrent(dbValue);
+ }
+ catch(com.sleepycat.db.DeadlockException e)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(_trace.errorPrefix + "Dbc.put: " + e.getMessage(),
+ _map.connection().currentTransaction());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException e)
+ {
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(e);
+ ex.message = _trace.errorPrefix + "Dbc.put: " + e.getMessage();
+ throw ex;
+ }
+ }
+ else
+ {
+ //
+ // Duplicate the cursor and move the entry
+ // element to update it (using the duplicate cursor)
+ //
+
+ com.sleepycat.db.Cursor clone = null;
+
+ try
+ {
+ clone = _cursor.dup(true);
+
+ //
+ // Not interested in data
+ //
+ com.sleepycat.db.DatabaseEntry dummy = new com.sleepycat.db.DatabaseEntry();
+ dummy.setPartial(true);
+
+ com.sleepycat.db.OperationStatus rc = clone.getSearchKey(entry.getDbKey(), dummy, null);
+
+ if(rc == com.sleepycat.db.OperationStatus.NOTFOUND)
+ {
+ NotFoundException ex = new NotFoundException();
+ ex.message = _trace.errorPrefix + "Dbc.get: DB_NOTFOUND";
+ throw ex;
+ }
+
+ byte[] v = _map.encodeValue(value, _map.connection().getCommunicator());
+ com.sleepycat.db.DatabaseEntry dbValue = new com.sleepycat.db.DatabaseEntry(v);
+ clone.putCurrent(dbValue);
+ }
+ catch(com.sleepycat.db.DeadlockException e)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(
+ _trace.errorPrefix + "EntryIterator.setValue: " + e.getMessage(),
+ _map.connection().currentTransaction());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException e)
+ {
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(e);
+ ex.message = _trace.errorPrefix + "EntryIterator.setValue: " + e.getMessage();
+ throw ex;
+ }
+ finally
+ {
+ if(clone != null)
+ {
+ closeCursor(clone);
+ }
+ }
+ }
+ }
+
+ private void
+ closeCursor(com.sleepycat.db.Cursor cursor)
+ {
+ try
+ {
+ cursor.close();
+ }
+ catch(com.sleepycat.db.DeadlockException e)
+ {
+ dead();
+ DeadlockException ex = new DeadlockException(
+ _trace.errorPrefix + "Dbc.close: " + e.getMessage(), _map.connection().currentTransaction());
+ ex.initCause(e);
+ throw ex;
+ }
+ catch(com.sleepycat.db.DatabaseException e)
+ {
+ DatabaseException ex = new DatabaseException();
+ ex.initCause(e);
+ ex.message = _trace.errorPrefix + "Dbc.close: " + e.getMessage();
+ throw ex;
+ }
+ }
+
+ private void
+ dead()
+ {
+ if(_cursor != null)
+ {
+ com.sleepycat.db.Cursor cursor = _cursor;
+ _cursor = null;
+ closeCursor(cursor);
+ }
+ }
+
+ private final MapI<K, V> _map;
+ private final IteratorModel<K, V> _model;
+
+ private final TraceLevels _trace;
+ private final String _dbName; // For use in finalizer.
+ private final com.sleepycat.db.Transaction _txn;
+ private com.sleepycat.db.Cursor _cursor;
+ private EntryI<K, V> _current;
+ private EntryI<K, V> _lastReturned;
+ private Object _iteratorListToken;
+}