All entries for Friday 09 December 2005
December 09, 2005
Serializing java objects to Oracle
We recently had a requirement to use our new Shibboleth based Single Sign On system with a cluster of jboss servers running an essentially stateless application.
The way that our new SSO works is through the SAML Post Profile meaning that an authentication assertion is posted by the user to the Shire service. This shire service then does an Attribute Request back to SSO and puts the results into a user cache in memory and generates a cookie which links to the user in the cache.
The problem is that the request might then go back to another member of the cluster which does not share the cache so it won't know about the user represented by the cookie. The obvious solution is some kind of clustered cache.
We've not needed to use any clustered cache technology before so passed on the likes of Coherence (insane pricing) and other open source caches such as memcached. It is best not to introduce new technologies that you can't support unless you have to.
I ended up building a simple two level cache that put the data both in memory and in the database. If when a request came in, there was nothing in the memory cache, it checked the database and populated the memory cache. I wouldn't want to go to the database everytime as this is a very busy application that could do without the additional overhead.
Now, the code.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(value);
} catch (IOException e) {
throw new RuntimeException("Could not write object to stream",e);
}
SqlUpdate su = new SqlUpdate(getDataSource(), "INSERT INTO objectcache " + "(key, objectdata,createddate) "
+ "VALUES (?, ?,?)");
su.declareParameter(new SqlParameter("key", Types.VARCHAR));
su.declareParameter(new SqlParameter("objectdata", Types.BLOB));
su.declareParameter(new SqlParameter("createddate", Types.DATE));
su.compile();
Object[] parameterValues = new Object[3];
parameterValues[0] = key.toString();
LobHandler lobHandler = new DefaultLobHandler();
parameterValues[1] = new SqlLobValue(baos.toByteArray(), lobHandler);
parameterValues[2] = new java.sql.Date(new Date().getTime());
su.update(parameterValues);
Not knowing how big these objects were going to be, I figured it would be best to put this in a blob, but that has its own joys, especially with plain old JDBC. I used Spring's very handy JDBC helpers to make my life easier. If you want to get the object back out:ObjectInputStream ois = new ObjectInputStream(new DefaultLobHandler().getBlobAsBinaryStream(resultSet, 1));
UserCacheItem dbItem = (UserCacheItem) ois.readObject();
return dbItem;
Basically just select back the object and use the ObjectInputStream to de-serialize the object back into existence. Simple.