You are here: Basics Operations & Concepts > Transparent Activation/Persistence > Adding the Configuration

Implementation

This topic explains how transparent activation/persistence works and how you can implement the required interfaces manually. In practice you should use the provided enhancer's instead of implementing the interfaces yourself. See "Transparent Persistence Enhancement Example"

Adding the Configuration

We need to explicitly configure transparent activation/persistence.

Transparent Activation

This adds transparent activation, which automatically activates objects.

final EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
configuration.common().add(new TransparentActivationSupport());
ObjectContainer container = Db4oEmbedded.openFile(configuration, DATABASE_FILE_NAME);
TransparentPersistence.java: Add transparent activation

Transparent Persistence

This adds transparent persistence, which automatically activates objects and manages changes on objects. This includes implicitly the transparent activation support.

Optionally you can specify how rollbacks are handled.

final EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
configuration.common().add(new TransparentPersistenceSupport(new DeactivatingRollbackStrategy()));
ObjectContainer container = Db4oEmbedded.openFile(configuration, DATABASE_FILE_NAME);
TransparentPersistence.java: Add transparent persistence

Implementing the Activatable Interface

In order to support Transparent Activation, the objects which are stored in the database need to implement the Activatable-interface.

An object which implements the Activatable-interface is responsible for activating itself. For this purpose the class needs a field to keep its activator. This field is only used by the transparent activation/persistence. Therefore it's marked as transient, to avoid that it is stored in the database. 

import com.db4o.activation.ActivationPurpose;
import com.db4o.activation.Activator;
import com.db4o.ta.Activatable;

public  class Person implements Activatable{

    private  transient Activator activator;
Person.java: Implement the required activatable interface and add activator

The implementation of the two methods of the Activatable-interface is straight forward. The bind-method binds an activator to the object. It's called by the transparent activation framework. The activate-method needs to be called before any read or write operation on the object. Since these two methods are always the same, you can move the implementation to a common super class or to a static utility class.

public  void bind(Activator activator) {
    if (this.activator == activator) {
        return;
    }
    if (activator != null && null != this.activator) {
        throw  new IllegalStateException("Object can only be bound to one activator");
    }
    this.activator = activator;
}

public  void activate(ActivationPurpose activationPurpose) {
    if(null!=activator){
        activator.activate(activationPurpose);
    }
}
Person.java: Implement the activatable interface methods

Now to the most important part. Every time a field of the class is accessed you need to call the activate-method with the purpose. This needs to be done in every getter/setter and method. Probably the best way is to use only getter/setter even within the class to access fields. And the getter/setter ensures that the activate-method is called.

public  void setName(String name) {
    activate(ActivationPurpose.WRITE);
    this.name = name;
}

public String getName()  {
    activate(ActivationPurpose.READ);
    return name;
}

public String toString()  {
    // use the getter/setter withing the class,
    // to ensure the activate-method is called
    return getName();
}
Person.java: Call the activate method on every field access

Implementing the Activatable-interface manually for every class is repetitive and error prone. That's why this process can be automated.See "Transparent Persistence Enhancement Example"

After transparent activation/persistence is enabled you can navigate into object-graph as deeply as you want. The transparent activation will load the objects from the database as you need them. When you've enabled transparent persistence updates are also done transparently.

{
    ObjectContainer container = openDatabaseWithTA();
    Person person = Person.personWithHistory();
    container.store(person);
    container.close();
}
{
    ObjectContainer container = openDatabaseWithTA();
    Person person = queryByName(container,"Joanna the 10");
    Person beginOfDynasty = person.getMother();

    // With transparent activation enabled, you can navigate deeply
    // nested object graphs. db4o will ensure that the objects
    // are loaded from the database.
    while(null!=beginOfDynasty.getMother()){
        beginOfDynasty = beginOfDynasty.getMother();
    }
    System.out.println(beginOfDynasty.getName());
    
    container.close();
}
TransparentActivationExamples.java: Transparent activation in action

Behavior in Mixed Mode

In some environments there are both, objects which implement the Activatable-interface on other which don't. What's the behavior in this scenario? Then the behavior is this:

That behavior ensures that you never run into not activated objects in the transparent activation / persistence mode.

However objects which do not implement the Activatable-interface are not updated with transparent persistence. You have to do that yourself or enhance those classes as well.