Howard Lewis Ship <hls...@gmail.com> wrote on 24/09/2009 21:34:06: > What about nestable manual scopes?
I was thinking of not allowing them because I wanted to give errors if you got the open()/close() mismatched. But actually, now I think about it, the manual scope is nested in a perthread scope, so I could warn about bad nesting when the thread cleans up, so nested scopes would be reasonable. -Paul > 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 --- 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.