In our latest development build we provide a first implementation of Transparent Activation and Transparent Persistence for standard Java collections.

In case you don't know what these terms mean:
Transparent Activation (TA) loads members of persistent objects lazily when they are accessed.
Transparent Persistence (TP) flags objects as dirty when their members are modified, so these objects are stored upon the next commit.

If you decide to work with TA and TP, you will not need any ObjectContainer#store() calls to update objects and no
ObjectContainer#activate() calls to activate object graphs. db4o does all the work nicely for you: transparently.

In order for TA and TP to work, persistent classes need to implement the Activatable interface.

Our Ant enhancer task com.db4o.enhance.Db4oEnhancerAntTask can add the necessary code to your persistent classes, as demonstrated in the Ant script further down in this posting.

Because we could not change the implementation of the standard Java collections we decided to derive classes
from them and to add the Activatable code in these derived classes.

The com.db4o.collections package now contains the following implementations:
ActivatableArrayList
ActivatableHashMap
ActivatableHashSet
ActivatableHashtable
ActivatableLinkedList
ActivatableStack
ActivatableTreeSet

The above is a complete list of all the collections that we support so far. Internally we have overridden all public methods. In these methods we call #activate() and then delegate to the parent methods. Please note that we have only added support for JDK 5 methods, because of backward compatibility issues of our build system. If you use JDK 6 methods you will run into problems.

In your code you do not have to use our derived collection classes. Our Ant enhancer task com.db4o.enhance.Db4oEnhancerAntTask will exchange all collection constructor calls in your code to create Activatable collections instead.

Let's create a small sample project that uses Transparent Persistence to check things out:

package com.db4o.sample;

import java.util.*;

public class Team {
	
	private String name;
	
	private List pilots;
	
	public Team(String name){
		this.name = name;
	}
	
	public void addPilot(Pilot pilot){
		if(pilots == null){
			pilots = new ArrayList();
		}
		pilots.add(pilot);
	}
	
	@Override
	public String toString() {
		String str = "Team " + name;
		if(pilots != null){
			str += " with pilots: ";
			for (Pilot p : pilots){
				str += p + " ";
			}
		}
		return str;
	}
	
	public String getName(){
		return name;
	}

}


package com.db4o.sample;

public class Pilot {
	
	private String name;
	
	public Pilot(String name){
		this.name = name;
	}
	
	@Override
	public String toString() {
		return name;
	}
	
}

package com.db4o.sample;

import java.io.*;

import com.db4o.*;
import com.db4o.config.*;
import com.db4o.cs.*;
import com.db4o.cs.config.*;
import com.db4o.query.*;
import com.db4o.ta.*;

public class Program {
	
	private static String FILE = "tp.db4o";
	
	private static int PORT = 4444;
	
	private ObjectContainer objectContainer;
	
	private ObjectServer objectServer;
	
	public static void main(String[] args) {
		new Program().run(); 
	}
	
	public void run() {
		deleteDatabaseFile();  // to make the sample rerunnable
		openObjectContainer();
		storeTeam();
		close();
		openObjectContainer();
		addPilots();
		close();
		openObjectContainer();
		printTeams();
		close();
	}

	private void deleteDatabaseFile() {
		new File(FILE).delete();
	}
	
	private void printTeams() {
		ObjectSet objectSet = objectContainer.query(Team.class);
		while(objectSet.hasNext()){
			System.out.println(objectSet.next());
		}
	}

	private void openObjectContainer(){
		openEmbeddedObjectContainer();
		// openClientServerObjectContainer();  
	}
	
	private void openEmbeddedObjectContainer(){
		EmbeddedConfiguration embeddedConfiguration = Db4oEmbedded.newConfiguration();
		embeddedConfiguration.common().add(new TransparentPersistenceSupport());
		objectContainer = Db4oEmbedded.openFile(embeddedConfiguration, FILE);
	}
	
	private void openClientServerObjectContainer(){
		ServerConfiguration serverConfiguration = Db4oClientServer.newServerConfiguration();
		serverConfiguration.common().add(new TransparentPersistenceSupport());
		objectServer = Db4oClientServer.openServer(serverConfiguration, FILE, PORT);
		objectServer.grantAccess("db4o", "db4o");
		
		ClientConfiguration clientConfiguration = Db4oClientServer.newClientConfiguration();
		clientConfiguration.common().add(new TransparentPersistenceSupport());
		objectContainer = Db4oClientServer.openClient(clientConfiguration, "localhost", PORT, "db4o", "db4o");
	}
	
	private void storeTeam(){
		Team team = new Team("Ferrari");
		objectContainer.store(team);
	}
	
	private void addPilots() {
		Team team = queryTeamByName("Ferrari");
		team.addPilot(new Pilot("Massa"));
		team.addPilot(new Pilot("Raikkonen"));
	}
	
	private Team queryTeamByName(final String name){
		ObjectSet objectSet = objectContainer.query(new Predicate() {
			@Override
			public boolean match(Team team) {
				return team.getName().equals(name);
			}
		});
		return objectSet.next();
	}

	private void close(){
		objectContainer.close();
		if(objectServer != null){
			objectServer.close();
		}
	}
	
}

We also need an Ant script that enhances our program for Transparent Persistence:

name="db4o.TP.sample" basedir="." default="run">
   
name="dir.src" value="${basedir}/src" />
   
name="dir.bin" value="${basedir}/bin" />

    id="project.classpath">
      
dir="lib">
         
name="**/*.jar"/>
      

   

    name="db4o-enhance" 
      classname="com.db4o.enhance.Db4oEnhancerAntTask"
      
classpathref="project.classpath" />

    name="compile">
      
dir="${dir.bin}" />
      
srcdir="${dir.src}" destdir="${dir.bin}" failonerror="true">
         
refid="project.classpath" />
      

   

    name="enhance" depends="compile">
      
classtargetdir="${dir.bin}" ta="true" nq="true" collections="true">
         
refid="project.classpath" />
         
dir="${dir.bin}">
            
name="**/*.class" />
         

      

   

    name="run" depends="enhance">
      
classname="com.db4o.sample.Program" failonerror="true">
         

            
path="${dir.bin}" />
            
refid="project.classpath" />
         

      

   

If you want to try this project out yourself all you need is the db4o-7.[version].[iteration].[build]-all-java5.jar in the lib folder of your project. For your convenience I have attached a full Eclipse project with the above sources and with the db4o-all.jar to this posting. If you now run the Ant script, it prints out:
Team Ferrari with pilots: Massa Raikkonen

Can you see the interesting part of this small project?
The #addPilots() method never has to call ObjectContainer#store(). Because the ArrayList in Team.pilots is exchanged with an ActivatableArrayList and because TransparentPersistenceSupport is added to the db4o configuration, it is sufficient to add the pilots to the list and they will be stored in the automatic commit of the close() operation. Isn't that nice and easy?

You are invited to experiment with db4o Transparent Persistence and to tell us about your experiences in the db4o forum.

Enjoy!