views:

359

answers:

1

(x-posted to guice mailing list)

I'm trialling Guice on a new library that will live in an existing application. All our apps right now are spring apps and we have some common code that is tied to spring, mainly to do with the thread model we tend to use. It basically gives us (what could be seen as) a logical thread.

So we can throw jobs at it and it ensures that jobs with a given key always end up on the same pipe in the order that they were submitted. Typically this is a single thread for the life of the application but if bad things happen then the worker thread (that backs the pipe) is thrown away, the pipe deactivated, a new worker created and the pipe reactivated on that worker. All the wiring here is provided by spring.

My new lib needs to use this for the thread model & I plan on using guice for the logic & domain side of things, i.e. constructing the work that goes on the pipeline & and the logic that it represents. This seems quite straightforward to me except for one thing that seems quite gnarly, namely that I want to inject certain things with "pipe" (aka logical thread) scope. I've read the custom scopes (and SimpleScope implementation) wiki page but some things are not clear to me and clarification would be much appreciated...

  1. pipes survive for the life of the JVM therefore it seems that I need to enter a scope but never exit, any downsides to this?
  2. what options do I have for triggering scope entry in a spring managed bean? is it just a case of creating the spring context and then using the SpringIntegration to suck in the spring beans into a guice context?
  3. does this sound really flaky and I should just wrap it with a singleton keyed by my pipe id instead?

Cheers Matt

A: 

I've implemented something which works but involves some slightly ugly setup... still interested in any improvements on this & there may be a bit too much code to post really so just put some snippets in that hopefully illuminates

it's a a variation on the SimpleScope example which involves;

  • bringing up the spring ctx
  • grabbing a specific bean out of it (that is a registry of pipeline keys)
  • passing that to the Guice module along with the beanfactory
  • giving that registry to the Scope impl so the scope is entered when the pipe is activated (which happens later when certain spring beans are init'ed)

It seems I have to grab the specific bean rather than access it through a Named after doing a bindAll on the beanfactory as the Scope instance is new'ed yourself in the Module, i.e.

    PipeScope<SecurityId> pipeScope = new PipeScope<SecurityId>();
    pipeScope.setPipeIdRegistry(pipeIdRegistry);
    bindScope(Pipe.class, pipeScope);
    bind(PipeScope.class)
            .annotatedWith(Names.named("pipeScope"))
            .toInstance(pipeScope);
    SpringIntegration.bindAll(binder(), beanFactory);

The fact I have to new it means I need to explicitly provide the registry to the module, can't see a way around this as it's a chicken & egg situation.

The PipeScope basically stores values against the pipe key (actually a List of keys) as opposed to a ThreadLocal so my enter is like

public void enter(List<K> scopedKeys) {
    checkState(values.get(scopedKeys) == null, "A scoping block is already in progress");
    values.put(scopedKeys, Maps.<Key<?>, Object>newHashMap());
}

all in all seems to function perfectly well... at least in my quickly knocked up test harness anyway

Matt