Committed callbacks have just been completed and checked in to SVN. You can now register a listener for the committed event and use it to keep all clients informed about changes committed by other clients.
The syntax to register a committed listener looks like this:
// Java
EventRegistry eventRegistry = EventRegistryFactory.forObjectContainer(objectContainer);
eventRegistry.committed().addListener(new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
}
});
// .NET
IEventRegistry registry = EventRegistryFactory.ForObjectContainer(Db());
registry.Committed += new CommitEventHandler(OnEvent);
public void OnEvent(object sender, Db4objects.Db4o.Events.CommitEventArgs args)
{
}
Now where and why is this new functionality helpful?
The really cool usecase is that you can keep objects on all clients in sync with committed changes, if you refresh objects from within the listener. That way you can make sure that the local cache always is updated automatically and you never ever again have to call #refresh() upon retrieval of objects in a query.
When working with the new functionality in a Client/Server setup you should be aware of the fact that the listener will be called from a different thread than your normal application so you will have to use synchronisation to guard your application from objects being modified behind it's back.
It also is good practice to remove listeners before shutting down your clients.
Below is a complete runnable sample application to demonstrate the new functionality. Notice the changed output when printing the same 'client2Car' object twice without any obvious intermediate modification:
Car: Ferrari 2006 Driver: Schumacher
Car: Ferrari 2007 Driver: Hakkinnen
And here is the code sample:
package com.db4o.db4ounit.common.assorted;
import java.io.*;
import com.db4o.*;
import com.db4o.events.*;
import com.db4o.ext.*;
import com.db4o.foundation.*;
public class PushedUpdatesSample {
private static final String FILE = "pushedUpdates.db4o";
private static final int PORT = 4440;
private static final String USER = "db4o";
private static final String PASSWORD = "db4o";
public static void main(String[] args) throws IOException {
new PushedUpdatesSample().run();
}
public void run() throws IOException{
new File(FILE).delete();
ObjectServer server = Db4o.openServer(FILE, PORT);
server.grantAccess(USER, PASSWORD);
ObjectContainer client1 = openClient();
ObjectContainer client2 = openClient();
waitForCompletion();
Car client1Car = new Car("Ferrari", 2006, new Driver("Schumacher"));
client1.set(client1Car);
client1.commit();
waitForCompletion();
Car client2Car = (Car) client2.query(Car.class).next();
System.out.println(client2Car);
client1Car.model = 2007;
client1Car.driver = new Driver("Hakkinnen");
client1.set(client1Car);
client1.commit();
waitForCompletion();
// This is the beef of this example.
// client2Car has been automatically updated because of the
// modification and the commit by client1
System.out.println(client2Car);
waitForCompletion();
client1.close();
client2.close();
server.close();
}
private ObjectContainer openClient() throws IOException {
ObjectContainer client = Db4o.openClient("localhost", PORT, USER, PASSWORD);
EventListener4 committedEventListener = createCommittedEventListener(client);
EventRegistry eventRegistry = EventRegistryFactory.forObjectContainer(client);
eventRegistry.committed().addListener(committedEventListener);
return client;
}
private EventListener4 createCommittedEventListener(final ObjectContainer objectContainer){
return new EventListener4() {
public void onEvent(Event4 e, EventArgs args) {
ObjectInfoCollection updated = ((CommitEventArgs)args).updated();
Iterator4 infos = updated.iterator();
while(infos.moveNext()){
ObjectInfo info = (ObjectInfo) infos.current();
Object obj = info.getObject();
objectContainer.ext().refresh(obj, 2);
}
}
};
}
private void waitForCompletion(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class Car {
public String name;
public int model;
public Driver driver;
public Car(String name, int model, Driver driver) {
this.name = name;
this.model = model;
this.driver = driver;
}
public String toString() {
return "Car: " + name + " " + model + " Driver: " + driver.name;
}
}
public static class Driver {
public String name;
public Driver(String name) {
this.name = name;
}
}
}