Online/offline data sync with Adobe AIR

This is a bit of a progress report. Bit light on actual wisdom, sorry – check back later for that.

I’ve been playing with Adobe AIR as a way to develop cross-platform intermittently online applications. I’ve already got a fully fledged Java domain model using Spring and Hibernate, so for the server side Spring’s BlazeDS integration is a real godsend – and it really is as easy to set up as it looks in the Adobe evangelist’s easy as falling off a log video. Flash Builder is pretty neat too, so all is good.

Local data storage is no drama, so one box left to tick – syncing offline data when we get back online.

There are some products that help with this:
Adobe’s LiveCycle Data Services – a vast, enterprise-grade JEE app. Not ruling it out, but hey, I just want to sync a couple of records – this is going to be a very lightweight app.
WebORB – OK, I’m a Tomcat noob, but I failed to get this running in two of three possible installation modes. The one that did work, the prepackaged install, doesn’t even let you change the server port. Guess what – 8080 is already taken (who would have thought?). I don’t want to diss WebORB, but between my install problems and the fact that I really don’t need or want another server, I’m moving on for now.
Farata’s Clear Toolkit. Does anyone else find Sourceforge to be a complete PITA? Every second download fails. In this case *every* download failed. Life is too short to spend it looking at a page full of blinking ads.

OK, so I’ve parked the off-the-shelf idea until I’ve built up a bit more desperation. So how hard can it be to code this up from scratch? The server side is taken care of, all I need is the client-side code.

With SQLite on the client side, the term “database replication” springs to mind. On reflection, though, what I have on the client side is really just a cache, not a database in the business sense of the word. A write-though fault-tolerant cache with pluggable fetch and store strategies would fit the bill nicely. There must be a ton of those already out there, right?

Wrong. Not for AS3, anyway. Please ping me if you know of one.

So that leaves me with two options:

  1. Futz around with native process calls and try to package something like ehCache with my app. Is ehCache really going to work on a phone? I’m nervous.
  2. Write an AS3 cache myself. Now, I have the deepest respect for anyone who has written a bug-free caching system – that’s a very select bunch of people. So I’m still nervous.

Of course the third option is that my Google chops are rubbish and some kind reader will post one of those humiliating “if you looked for 0.7 seconds you would have found this” comments. Here’s hoping.

Spring/Hibernate unit testing part 2

The basic Spring transactional testing approach is great for testing domain logic. If you want to test your persistence layer, though, it falls short in some important ways. Most importantly, with the usual approach you will never actually load an object from the database. All the objects you create will hang around in Hibernate’s session cache, and will always be fetched from there. Even objects you created in a @Before method will be within the one Hibernate session.

As an example of why this matters, you can misspell your primary key name in the hibernate mapping file, and these tests will never tell you. Don’t ask me how I know 🙂

The solution is to create some test data before the main test transaction kicks in. That has some significant disadvantages, so I only do it for test classes that are specifically testing the persistence layer. What are the disadvantages?

  • If something goes wrong with your setup or teardown code you can be left with a dirty database and you’ll have to clean up before any further tests will work. In a CI environment that can be a real pain, so ideally you’d be regenerating your test database after each run of the persistence tests.
  • Because you need three transactions per test, it’s significantly slower
  • You have to write the transactional boilerplate for setup and teardown

So, it’s worth doing, but it by no means replaces the basic single-transaction approach. Most of your tests should still be using that approach.

In use, the persistence test class looks something like this:

@ContextConfiguration(locations={"/myApplicationContext.xml"})
public class MyPersistenceTests extends  AbstractTransactionalJUnit4SpringContextTests   {
        @Resource protected SessionFactory sf;
	@Resource protected org.springframework.orm.hibernate3.HibernateTransactionManager txManager;

	@BeforeTransaction
	public void setupBeforeTransaction() {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("SomeTxName");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

		TransactionStatus status = txManager.getTransaction(def);
		try {
			// Your setup code here
			txManager.commit(status);
		}
		catch (Exception e) {
			txManager.rollback(status);
			throw new Error (e);
		}
	}
	
	@AfterTransaction
	public void teardownAfterTransaction() {
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("SomeTxName");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

		TransactionStatus status = txManager.getTransaction(def);
		try {
			// your teardown code here
			txManager.commit(status);
		}
		catch (Exception e) {
			txManager.rollback(status);
			throw new Error (e);
		}

               // Your test methods here
	}

We’re still extending the same Spring base class as before. We’ve just injected our transaction manager and added a couple of methods. The @BeforeTransaction and @AfterTransaction annotations are provided by Spring for exactly this use case. Spring will still wrap our test methods in a transaction automatically, and still roll it back after each method invocation.

So now in our test methods we can load any of the objects we created in our “before transaction” code and be sure we are hitting the database.

After writing 20 or 30 of these persistence test classes you start to notice that they all look very similar. Create an object. Make sure you can load it. Tear it down. This is even more pronounced if you use a base domain object class as I do. In my next post I’ll talk about some techniques for writing abstract test classes that do most of the repetitive stuff.

Spring/Hibernate unit testing

Spring provides some nice tools to assist in unit testing with Hibernate, which are well covered in Spring’s excellent documentation. I want to recap some basics here, though. Later on I want to talk about persistence layer test generation, and I’ll need to refer back to these notes.

One of Spring’s convenient tools is a base test class that does a number of nifty things:

  • Sets up your application context, including Hibernate SessionFactory if you have one.
  • Uses that context to do DI into your test classes, which is a nice way to access your singletons within your tests.
  • Wraps each test method in a transaction which gets rolled back at the end of the method. Complete test isolation with zero work on your part!

In use, it looks something like this:

// This tells spring where to find my config.  Note that this could be a special test config rather than my production config
@ContextConfiguration(locations={"/myApplicationContext.xml"})
public class MyContextTests extends  AbstractTransactionalJUnit4SpringContextTests   {
	
        // Standard Spring DI
	@Resource protected SessionFactory sf;
	
       // a basic unit test (utility methods omitted).  Note that I'm creating new objects and flushing them to the database,
       // but not bothering to clean up in any way.
	@Test
	public void testCategoryManager_createDuplicateInDifferentService() {		
		Category category = createCategory("PCTEST");
		assertEquals("PCTEST", category.getName());
		sf.getCurrentSession().flush();	
		createCategoryFromOtherService("PCTEST");
	}	
}

This is a godsend for most test scenarios. It falls down in some ways, though, and I’ll talk about that in my next post.