All entries for August 2005

August 26, 2005

Spring web flow

Writing about web page

So I have been using spring web flow on my current project (thanks to Dave Hewitt ;)), and I gotta say, it really is nice.

It isn't a public release yet, so there are still teething problems, and the APIs do change (always um, interesting :)).

Basically, as the name suggests, it introduces the concept of a "flow". Typically, in web apps you have the concept of a request, a session or an application. There is no concept of a "process" scope. If, in typical web usage, your users do one or more "processes" within a single browser, then what can you do? You do not want to store information in the session (too large) or in the request (too small), so you are stuffed. Enter "flow scope".

Basically web flow allows you to model "flows" (hence the name obviously :)). Each flow has an xml document (or can be built in java) consisting of one or more actions, each action leads to a transition depending on the result of that action. Each transition can be another action, a sub flow (excellent concept) or a view. The view has transitions and so on until event you hit an end-state.

Implementation of processes or workflow within web apps is usually artificially demarcated around page renderings. This is because most MVC infrastructure is demarcated by the V, the view. With webflow there is no such restriction. For example, you could have a flow with 0 or multiple page views within that flow.

So how is data stored, well in the "flow" scope scope of course ;). I can already hear you saying so it is just clever session management, but no, it isn't :) Webflow being spring is architected to let you replace which ever bits you want, and there are multiple implementations of FlowExcecutionStorage, session backed, db backed or client side (through serialization). I am currenly using clientSide so there is no session state whatsoever ;) When I need to store really big objects (i.e. file uploads) then I just write a listener which dumps out the big objects to secondary storage when dehydrating the flow scope, and restores them when rehydrating :) And as mentioned, because of Spring's excellent architecture, this is all transparent.

Why did I start of with talking about flow storage instead of the workflow aspects? Because there are so many projects that are tripping over themselves because they don't want to use storage, but request scope isn't enough. SWF is a perfect fit even if the actually process, or workflow they are modelling isn't complicated. SWF provides you with native support for "flow scope". This in itself is a huge win :)

Take a typical request; user fills in a form and can upload 1 or more files. How do you cope with this? You could temporarily persist in secondary storage (file, DB) some representation of the user's results, or you can stick the object in the session. Sessions are not ideal for many reasons (timeout, memory constraints, replication etc.). SWF is a perfect solution for this.

Checkboxes + spring: howto

Writing about web page

So in viewing the spring forums, I keep seeing the same question coming up, how to manage subsets (i.e. checkboxes) in spring. This is my answer: link

August 24, 2005

hibernate and their stupid error messages ;)

So I have a Page, which has a Lock. Because lock only exists within a Page it was modelled as a component. Fine.

Unfortunately if a page is locked, sometimes all child pages need to be locked, and this potentially means 1000s of pages needing to be locked. As the lock is done via the object model, we very quickly run into memory problems. So I decided to model Lock as a seperate object (ta Chris May for the idea) with a link to the Page. 1000s of Lock objects is fine.

Anyways, I did this via one-to-one, with cascade="all-delete-orphan" on the Page, and creating a lock works. Deleting a page also deletes the lock, but how the flip do you remove just the lock! Calling page.setLock(null) fails. Calling lock.setPage(null) fails!

So in the end I gave up and modelled it as Page has many Locks. Page internally has a Set of locks, and setLock(Lock) just removes all existing locks and adds the new lock, so the set will only ever contain a single Lock.

Unfortunately I started getting this helpful error:

org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
at org.hibernate.jdbc.BatchingBatcher.checkRowCount(
at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(
at org.hibernate.jdbc.AbstractBatcher.executeBatch(
at org.hibernate.engine.ActionQueue.executeActions(
at org.hibernate.engine.ActionQueue.executeActions(
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(
at org.hibernate.impl.SessionImpl.flush(
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(
at junit.framework.TestCase.runBare(
at junit.framework.TestResult$1.protect(
at junit.framework.TestResult.runProtected(
at junit.framework.TestSuite.runTest(
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(

It turns out that setLock(null) added a null object to the Set of locks which hibernate could not then persist. This (I presume) happens because hibernate first does an insert to create the page lock record, then does a corresponding update to create the reference to the parent. Kinda fishy really. I would either expect hibernate to blow up saying cannot persist null, or to simply skip that entry. I wouldn't expect it to do the insert but not the update!

Not adding nulls to the set works fine. Not that I should be using a stinking one-2-many to model a one-2-one in the first place!!!!

Hibernate, love it or hate it, or in this situation, both!

August 17, 2005

Spring AOP rocks (as expected ;))

Writing about web page

So in general, I am a big fan of the decorator pattern. This pattern very nicely allows you to have individual wrappers that deal with a single concern, for example:

interface SomeService {
  Object doSomething(final Object param);

if you want to wrap this with a caching wrapper, then a DelegateDecorator works well:

final class CachingSomeService implements SomeService {
  private final SomeService delegate;
  private final Map map = new HashMap();
  public CachingSomeService(final SomeService theDelegate) {
    this.delegate = theDelegate;

  public final Object doSomething(final Object param) {
    if (!map.contains(param)) {
      map.put(param, delegate.doSomething(param));
    return map.get(param);

you get the idea ;)

Well this works really well unless you only want to provide extra functionality for a single method, in which case you end up with a lot of methods that don't do anything except delegate, which is a bit smelly.

Spring AOP (actually just AOP) provides the answer ;) If you aren't familiar with, or haven't used AOP, then it takes a while to get your head around what it is, and how it works. Coupled with the fact that they use the most stupid terminology ever; it isn't easy :)

Anyways, rather then create another decorator, I now create an MethodInterceptor. This is a bit of code "wraps" the method I am adding functionality to. It looks like:

public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
        Object[] args = methodInvocation.getArguments();
        Object param = args[0];
        if (!map.contains(param)) {
          map.put(param, methodInvocation.proceed());
        return map.get(param);

(one nasty thing is you loose type safety :()

I then need to tell Spring to wrap the bean with this interceptor. I do this by using a pointcut. A pointcut basically defines a position within code. Spring has a concept of an Advisor (combination of Advice and Pointcut), and a useful regexp based implements:

bean id="cachingAdvisor" class=""
    property name="advice" ref="cachingMethodInterceptor"
    property name="patterns"
        value .* value 

So we now have an Advisor detailing what we want to do, and where we want to do it.

The final piece is to "wrap" the "delegate", the original service implementation. We can do that through a FactoryBean, specifically, a ProxyFactoryBean:

bean id="myServiceTarget" class="MyServiceImpl"

   bean id="myService" class="org.springframework.aop.framework.ProxyFactoryBean"
    property name="proxyInterfaces" value="MyService"
    property name="target" ref="myServiceTarget"
    property name="interceptorNames"
        value cachingAdvisor value

Thus, when anyone asks for the bean "myService" they get a proxy that delegates all matching methods to cachingAdvisor. Any methods that don't match go straight through to the delegate (myServiceTarget).

Cool eh ;)

OK, as always there are pros and cons, pros:

  • cut down and empty delegateDecorators
  • configuration is done in the XML, where it should be
  • reuse advisor whereever (imagine a debugging advisor which will work for any method ;))


  • configuration is quite complicated
  • refactoring will break the advisor because of the lack of type safety. It will also potentially break the pointcut declaration
  • have to look at the configuration to see what is being done (which might actually be a good thing ;))
  • easy to break a whole chain of things because it is not being applied where you think it is
  • difficult to debug because you cannot see which classes are being used, you only see a "proxy$x" class.

Still all in all, an extremely powerful thing. It really comes into it's own when you start applying the same bit of code to lots of different places, i.e. transactions, security etc.

August 11, 2005

Useful hibernate blog ;)

Writing about web page

So whilst struggling with the wonder that is CGLIB and hibernate proxies and lazy loading, I stumbled across link which is a very useful link.

In summary, hibernate 3 makes everything lazy including classes. This means that unless you explictly define a proxy element you will get a CGLIB class. Unfortunately CGLIB won't work if your class or any methods are final. Since lazy loading of classes isn't really that useful, turning off lazy loading would seem a sensible option. Unfortunately this means that all single point associates (one-to-one, many-to-one) are eagerly loaded, regardless of how they themselves are defined :)

As a matter of course, I always define an interface which my domain objects implement, and thus use proxies.

August 10, 2005

spring rocks ;) Filters + DI solved!

Writing about web page

So I have a couple of filters which need access to spring beans. Previously I was doing something like:

protected final void initFilterBean() throws ServletException {
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
pageResolver = (PageResolver) wac.getBean("pageResolver");

which was a bit fragile. Anyways, spring allows you to define filters in your applicationContext, complete with DI ;)

in web.xml:


Spring will then look for a bean called loadPageFilter in the applicationContext and delegate to that. And of course, you can specify the actual bean name (instead of using the filter-name).


P.S. Someone asked me how to do this and I forgot I had blogged about it, I redid this here: link

August 2005

Mo Tu We Th Fr Sa Su
Jul |  Today  | Sep
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31            

Search this blog



Most recent comments

  • Interesting… While I'm not completely convinced in such microbenchmarks, I'm pretty sure that 1ms … by Alexander Snaps on this entry
  • Hello. I bought the book yesterday. I was trying to find the source code for chapter 11 and chapter … by Suleman on this entry
  • by live mashup demo on this entry
  • Thanks mate ….. This blog was really helpful. by Maaz Hurzuk on this entry
  • Ty. Not directly helpful for my problem, but pointed me in the right direction. You will also get th… by Mike E. on this entry

Blog archive

Not signed in
Sign in

Powered by BlogBuilder