/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.internal.activation;
import com.db4o.*;
import com.db4o.events.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
import com.db4o.reflect.generic.*;
import com.db4o.ta.*;
public class TransparentActivationDepthProviderImpl implements ActivationDepthProvider, TransparentActivationDepthProvider {
public ActivationDepth activationDepth(int depth, ActivationMode mode) {
if (Integer.MAX_VALUE == depth)
return new FullActivationDepth(mode);
return new FixedActivationDepth(depth, mode);
}
public ActivationDepth activationDepthFor(ClassMetadata classMetadata, ActivationMode mode) {
if (isTAAware(classMetadata))
return new NonDescendingActivationDepth(mode);
if (mode.isPrefetch())
return new FixedActivationDepth(1, mode);
return new DescendingActivationDepth(this, mode);
}
private boolean isTAAware(ClassMetadata classMetadata) {
final GenericReflector reflector = classMetadata.reflector();
return reflector.forClass(Activatable.class).isAssignableFrom(classMetadata.classReflector());
}
private RollbackStrategy _rollbackStrategy;
public boolean _transparentPersistenceIsEnabled;
/* (non-Javadoc)
* @see com.db4o.internal.activation.TransparentActivationDepthProvider#enableTransparentPersistenceSupportFor(com.db4o.internal.InternalObjectContainer, com.db4o.ta.RollbackStrategy)
*/
public void enableTransparentPersistenceSupportFor(InternalObjectContainer container, RollbackStrategy rollbackStrategy) {
flushOnQueryStarted(container);
_rollbackStrategy = rollbackStrategy;
_transparentPersistenceIsEnabled = true;
}
private void flushOnQueryStarted(InternalObjectContainer container) {
final EventRegistry registry = EventRegistryFactory.forObjectContainer(container);
registry.queryStarted().addListener(new EventListener4() {
public void onEvent(Event4 e, final EventArgs args) {
objectsModifiedIn(transactionFrom(args)).flush();
}
});
}
protected Transaction transactionFrom(EventArgs args) {
return (Transaction) ((TransactionalEventArgs) args).transaction();
}
/* (non-Javadoc)
* @see com.db4o.internal.activation.TransparentActivationDepthProvider#addModified(com.db4o.internal.Transaction, java.lang.Object)
*/
public void addModified(Object object, Transaction transaction) {
if (!_transparentPersistenceIsEnabled)
return;
objectsModifiedIn(transaction).add(object);
}
public void removeModified(Object object, Transaction transaction) {
if (!_transparentPersistenceIsEnabled)
return;
objectsModifiedIn(transaction).remove(object);
}
private final TransactionLocal<ObjectsModifiedInTransaction> _objectsModifiedInTransaction = new TransactionLocal<ObjectsModifiedInTransaction>() {
@Override public ObjectsModifiedInTransaction initialValueFor(final Transaction transaction) {
final ObjectsModifiedInTransaction objectsModifiedInTransaction = new ObjectsModifiedInTransaction(transaction);
transaction.addTransactionListener(new TransactionListener() {
public void postRollback() {
objectsModifiedInTransaction.rollback(_rollbackStrategy);
}
public void preCommit() {
objectsModifiedInTransaction.flush();
}
});
return objectsModifiedInTransaction;
}
};
private ObjectsModifiedInTransaction objectsModifiedIn(Transaction transaction) {
return transaction.get(_objectsModifiedInTransaction).value;
}
private static final class ObjectsModifiedInTransaction {
private final IdentitySet4 _removedAfterModified = new IdentitySet4();
private final IdentitySet4 _modified = new IdentitySet4();
private final Transaction _transaction;
public ObjectsModifiedInTransaction(Transaction transaction) {
_transaction = transaction;
}
public void add(Object object) {
if (contains(object))
return;
_modified.add(object);
}
public void remove(Object object) {
if (!contains(object))
return;
_modified.remove(object);
_removedAfterModified.add(object);
}
private boolean contains(Object object) {
return _modified.contains(object);
}
public void flush() {
storeModifiedObjects();
_modified.clear();
}
private void storeModifiedObjects() {
final ObjectContainerBase container = _transaction.container();
container.storeAll(_transaction, _modified.valuesIterator(), container.updateDepthProvider().unspecified(new ModifiedObjectQuery() {
public boolean isModified(Object obj) {
return contains(obj);
}
}));
_transaction.processDeletes();
}
public void rollback(RollbackStrategy rollbackStrategy) {
applyRollbackStrategy(rollbackStrategy);
_modified.clear();
}
private void applyRollbackStrategy(RollbackStrategy rollbackStrategy) {
if (null == rollbackStrategy)
return;
applyRollbackStrategy(rollbackStrategy, _modified.valuesIterator());
applyRollbackStrategy(rollbackStrategy, _removedAfterModified.valuesIterator());
}
private void applyRollbackStrategy(RollbackStrategy rollbackStrategy, final Iterator4 values) {
final ObjectContainer objectContainer = _transaction.objectContainer();
while (values.moveNext()) {
rollbackStrategy.rollback(objectContainer, values.current());
}
}
}
}