Warp :: db4objects integration

Warp it! Store it! Get going in seconds! new!

Wideplay's integration for db4objects

Db4objects is a very simple, lightweight pure java object database. There is no relational mapping side, and you work directly with native Java objects. Warp-persist supports db4o integration with the Persistence support module. Simply drop the jar in and follow the instructions below to get going with various typical usage profiles.

The db4o integration was contributed by Jeff Chung. Thanks very much to Jeff for a wonderful job!

Enabling Persistence Support

To enable persistence support, configure the module when creating your injector:

Injector injector = Guice.createInjector(..., PersistenceService.usingDb4o()
			 .buildModule());
 

You must bind in the name of a file db4o can use as its data store in one of your own modules, for instance:

bindConstant().annotatedWith(Db4Objects.class).to("mystore.dat");

This creates a (or uses an existing) db file named mystore.dat. Alternatively, you can connect to a db4o object server at a remote location:

bindConstant().annotatedWith(Db4Objects.class).to("mystore.dat");

bindConstant().annotatedWith(Names.named(Db4Objects.HOST)).to("localhost");
bindConstant().annotatedWith(Names.named(Db4Objects.PORT)).to(4321);
bindConstant().annotatedWith(Names.named(Db4Objects.USER)).to("autobot");
bindConstant().annotatedWith(Names.named(Db4Objects.PASSWORD)).to("morethanmeetstheeye");
 

Finally, you must decide when the persistence service is to be started by invoking start() on the PersistenceService. I typically use a simple initializer class that I can bind and invoke at a time of my choosing:

public class MyInitializer { 
	@Inject MyInitializer(PersistenceService service) {
		service.start();
	} 
} 

A really simple approach would be to bind MyInitializer as an eager singleton so the PersistenceService is started up when Guice starts up; but I recommend you think about how it fits into your particular deployment environment before doing so.

Session-per-transaction strategy

This is a popular strategy, where a db4o ObjectContainer is created and destroyed around each database transaction. To use it, set the PersistenceModule's configuration accordingly:

Injector injector = Guice.createInjector(..., PersistenceService
			.usingDb4o()
			.across(UnitOfWork.TRANSACTION)
			.buildModule());
 

Note: this is the default UnitOfWork strategy even if unspecified (as in the earlier example).

Using the ObjectContainer inside Transactions

Once you have the injector created, you can freely inject and use an ObjectContainer in your transactional services:

import com.wideplay.warp.persist.Transactional;
import com.db4o.ObjectContainer;
... 
 
public class MyService {
	@Inject Provider<ObjectContainer> oc; 
 
	@Transactional 
	public void createNewPerson() {
		oc.get().set(new Person(...)); 
	} 
 

Note that since we are using a session-per-transaction strategy, you cannot hold a reference to the ObjectContainer instance across transactions (must obtain it from the provider each time). See the session-per-http-request strategy if this doesn't work for you.

Transaction semantics

See the transactions guide for detailed information. The only difference in db4o is that a transaction is always active when you have an ObjectContainer active. So @Transactional methods only commit transactions when they end. This is generally not a problem if you use session-per-transaction strategy or confine all your work to transactional methods. If you work with an ObjectContainer outside an @Transactional method, you should be aware that you will also participate in a transaction. So use it carefully.

Usage in Web Environments (session-per-http-request)

So far, we've only used a session-per-transaction strategy. In web environments this is atypical, and generally session-per-http-request is preferred (such as with the popular open-session-in-view paradigm). To enable this strategy, you first need to add a filter to web.xml:

	<filter>
		<filter-name>sessionPerRequestFilter</filter-name>
		<filter-class>com.wideplay.warp.db4o.SessionPerRequestFilter</filter-name>
	</filter>
	<filter-mapping>
		<filter-name>sessionPerRequestFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
 

It doesn't really matter where this filter appears (however, if you are using warp-widgets, it must appear before WidgetFilter). Then in your injector configuration:

Injector injector = Guice.createInjector(..., PersistenceService
			.usingDb4o()
			.across(UnitOfWork.REQUEST)
			.buildModule());
 
 

Note that with this configuration you can run multiple transactions within the same request (and the same ObjectContainer). This fits well with open-session-in-view. Remember however that in db4o a transaction is always active, regardless of whether you are inside an @Transactional method or not. This is not a big problem if you confine all your work to these methods, or understand that they represent transaction boundaries, not isolation.