What about nestable manual scopes? On Thu, Sep 24, 2009 at 1:29 PM, Paul Field <paul.fi...@db.com> wrote:
> There was a recent thread that discussed implementing the equivalent of > Spring's "prototype" beans in Tapestry IOC. I was of the opinion that it > wasn't possible to implement sensibly: you either run the risk of the > service living too long or else Tapestry's proxies would mean that you > created a new instance for every method call. > > I've been thinking about this some more, and I've realised that the > problem is about controlling the scope. Prototype beans in Spring are a > bit problematic anyway and the reason is that the scope is started by a > request to the container for the bean and then ended by the last reference > being removed (GC). Sometimes the "call to the container" is hidden - so > it's not very clear exactly what the scope is and that would be > particularly true in Tapestry where the proxies and @Inject mechanisms > hide the container well away from the client code. > > So I think that the key to doing a similar thing in Tapestry IOC is to > make control of the scope explicit. This would be known as "manual" scope > and the pattern would be something like this: > > > ----------------- > // This is provided by a hypothetical library and is actually 'perthread' > scoped - so your manual scope is nested within a thread > public interface ManualScope { > // Opens the scope - error if already open > void open(); > > // Closes the scope - error if not open > void close(); > > // Runs 'r' inside the scope - error if scope is already open > void run(Runnable r); > } > > ----------------- > // This is your module creating your manually-scoped service (somewhat > equivalent to a spring prototype bean) > public class MyModule { > public static void bind(ServiceBinder binder) { > binder.bind(MyService.class, MyServiceImpl.class).scope("manual"); > } > } > > ----------------- > // This is your client code using the service > > @Inject ManualScope manualScope; > @Inject MyService myManualScopedService; > > > public void doSomethingOldSchool() { > manualScope.open() > try { > myManualScopedService.doSomething(); > myManualScopedService.doSomeMore(); > } finally { > manualScope.close(); > } > } > > > public void doSomethingNewSchool() { > manualScope.run(new Runnable() { > public void run() { > myManualScopedService.doSomething(); > myManualScopedService.doSomeMore(); > } > }); > } > > > So the idea is that you can only use myManualScoped bean within the > open()/close() pair, or within the run(). If you use it outside, you get a > helpful exception. > > > There other options for 'prototype' beans I can think of involve not > having a service. Either: > 1) Create a factory service; the client code injects the factory and calls > a create() method. > 2) Inject ObjectLocator and call autobuild() (gives you the benefit of > dependency injection for a non-service object) > > Both of these are much simpler for the client. The manual scope is a bit > clunky to use. The main benefit is that the service is a proper IOC > service you can decorate it/advise it/override it and all kinds of other > good IOC stuff. In addition, you have complete control over the lifetime > of your service and potentially there could be a > ManualScopeCleanupListener (similar to ThreadCleanupListener) to clean-up > services when the scope closes. > > I'm pretty sure my work project would find it useful as, in Spring, I have > one-shot "commands" that are prototype beans and we use Spring's AOP to > add-on transactions, logging and auditing. This Manual scope idea would > work quite well for that as we could use the IOC's decorating/advising > capabilities. > > > However, I'm not convinced that the clunkyness of the client code won't > put people off using it and I'm not convinced that there are enough times > that you want to use IOC magic (such as advice) on a "prototype bean". So, > I'd appreciate some feedback on the idea. > > Can you think of any simplification I could make that makes it less > clunky? Would you use it? Is it useful enough for me to write the > implementation as open source? Useful enough to pester the committers to > put it in the core IOC? Or just a bad idea that I've had late one evening > :-) > > Thanks, > > - Paul > > > > --- > > This e-mail may contain confidential and/or privileged information. If you > are not the intended recipient (or have received this e-mail in error) > please notify the sender immediately and delete this e-mail. Any > unauthorized copying, disclosure or distribution of the material in this > e-mail is strictly forbidden. > > Please refer to http://www.db.com/en/content/eu_disclosures.htm for > additional EU corporate and regulatory disclosures. -- Howard M. Lewis Ship Creator of Apache Tapestry The source for Tapestry training, mentoring and support. Contact me to learn how I can get you up and productive in Tapestry fast! (971) 678-5210 http://howardlewisship.com