/* 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.ta;
import com.db4o.*;
import com.db4o.activation.*;
import com.db4o.config.*;
import com.db4o.events.*;
import com.db4o.foundation.*;
import com.db4o.internal.*;
import com.db4o.internal.activation.*;
import com.db4o.internal.diagnostic.*;
import com.db4o.internal.references.*;
import com.db4o.reflect.*;
// TODO: unbindOnClose should be configurable
/**
* Configuration item that enables Transparent Activation Mode for this
* session. TA mode should be switched on explicitly for manual TA implementation:
* <br><br>
* configuration.add(new TransparentActivationSupport());
* @see TransparentPersistenceSupport
*/
public class TransparentActivationSupport implements ConfigurationItem {
public void prepare(Configuration configuration) {
// Nothing to do...
}
/**
* Configures the just opened ObjectContainer by setting event listeners,
* which will be triggered when activation or de-activation is required.
*
* @param container the ObjectContainer to configure
* @see TransparentPersistenceSupport#apply(InternalObjectContainer)
*/
public void apply(final InternalObjectContainer container) {
if (isTransparentActivationEnabledOn(container))
return;
final TransparentActivationDepthProviderImpl provider = new TransparentActivationDepthProviderImpl();
setActivationDepthProvider(container, provider);
EventRegistry registry = eventRegistryFor(container);
registry.instantiated().addListener(new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
bindActivatableToActivator((ObjectEventArgs) args);
}
});
registry.created().addListener(new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
bindActivatableToActivator((ObjectEventArgs) args);
}
});
registry.closing().addListener(new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
final InternalObjectContainer objectContainer = (InternalObjectContainer) ((ObjectContainerEventArgs)args).objectContainer();
unbindAll(objectContainer);
if (!isEmbeddedClient(objectContainer)) {
setActivationDepthProvider(objectContainer, null);
}
}
});
final TADiagnosticProcessor processor = new TADiagnosticProcessor(container);
registry.classRegistered().addListener(new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
ClassEventArgs cea = (ClassEventArgs) args;
processor.onClassRegistered(cea.classMetadata());
}
});
}
public static boolean isTransparentActivationEnabledOn(final InternalObjectContainer container) {
return activationProvider(container) instanceof TransparentActivationDepthProvider;
}
private void setActivationDepthProvider(final InternalObjectContainer container,
final ActivationDepthProvider provider) {
container.configImpl().activationDepthProvider(provider);
}
private EventRegistry eventRegistryFor(final ObjectContainer container) {
return EventRegistryFactory.forObjectContainer(container);
}
private void unbindAll(final InternalObjectContainer container) {
Transaction transaction = container.transaction();
// FIXME should that ever happen?
if(transaction == null) {
return;
}
ReferenceSystem referenceSystem = transaction.referenceSystem();
referenceSystem.traverseReferences(new Visitor4() {
public void visit(Object obj) {
unbind((ObjectReference) obj);
}
});
}
private void unbind(final ObjectReference objectReference) {
final Object obj = objectReference.getObject();
if (obj == null || !(obj instanceof Activatable)) {
return;
}
bind(obj, null);
}
private void bindActivatableToActivator(ObjectEventArgs oea) {
Object obj = oea.object();
if (obj instanceof Activatable) {
final Transaction transaction = (Transaction) oea.transaction();
final ObjectReference objectReference = transaction.referenceForObject(obj);
bind(obj, activatorForObject(transaction, objectReference));
}
}
private void bind(Object activatable, final Activator activator) {
((Activatable) activatable).bind(activator);
}
private Activator activatorForObject(final Transaction transaction, ObjectReference objectReference) {
if (isEmbeddedClient(transaction)) {
return new TransactionalActivator(transaction, objectReference);
}
return objectReference;
}
private boolean isEmbeddedClient(Transaction transaction) {
return isEmbeddedClient(transaction.objectContainer());
}
Transaction transaction(EventArgs args) {
return (Transaction) ((TransactionalEventArgs)args).transaction();
}
protected static ActivationDepthProvider activationProvider(InternalObjectContainer container) {
return container.configImpl().activationDepthProvider();
}
private boolean isEmbeddedClient(final ObjectContainer objectContainer) {
return objectContainer instanceof ObjectContainerSession;
}
private final class TADiagnosticProcessor {
private final InternalObjectContainer _container;
public TADiagnosticProcessor(InternalObjectContainer container) {
_container = container;
}
public void onClassRegistered(ClassMetadata clazz) {
// if(Platform4.isDb4oClass(clazz.getName())) {
// return;
// }
ReflectClass reflectClass = clazz.classReflector();
if (activatableClass().isAssignableFrom(reflectClass)) {
return;
}
if (hasNoActivatingFields(reflectClass)) {
return;
}
NotTransparentActivationEnabled diagnostic = new NotTransparentActivationEnabled(
clazz);
DiagnosticProcessor processor = _container.handlers().diagnosticProcessor();
processor.onDiagnostic(diagnostic);
}
private ReflectClass activatableClass() {
return _container.reflector().forClass(Activatable.class);
}
private boolean hasNoActivatingFields(ReflectClass clazz) {
ReflectClass curClass = clazz;
while (curClass != null) {
final ReflectField[] fields = curClass.getDeclaredFields();
if (!hasNoActivatingFields(fields)) {
return false;
}
curClass = curClass.getSuperclass();
}
return true;
}
private boolean hasNoActivatingFields(ReflectField[] fields) {
for (int i = 0; i < fields.length; i++) {
if (isActivating(fields[i])) {
return false;
}
}
return true;
}
private boolean isActivating(final ReflectField field) {
ReflectClass fieldType = field.getFieldType();
return fieldType != null && !fieldType.isPrimitive();
}
}
}