Interesting problem. I've heard this referred to as the "Multiton" pattern.

Dhanji.

On Fri, Oct 15, 2010 at 3:27 AM, Fred Faber <ffa...@faiser.com> wrote:

> Basically you have a factory that should return a singleton instance for
> each unique string value passed into it?
>
> FactoryProvider won't do this for you out of the box, as it will create a
> new instance per invocation (as you've illustrated).
>
> What I would do in this case is to decorate your factory with an
> implementation that controls singletonness:
>
> interface CacheFactory {
>   // This can be named anything you want, not just "create"
>   NamedCache create(String name);
> }
>
> class CachingCacheFactory implements CacheFactory {
>
>  private final CacheFactory underlyingFactory;
>
>  //
> http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/MapMaker.html
>  private final Map<String, NamedCache> caches = new MapMaker()
>       .makeComputingMap(new Function<String, NamedCache>(){
>            @Override public NamedCache apply(String name) {
>                 return underlyingFactory.create(name);
>           }
>       });
>
>   @Inject
>   CachingCacheFactory {
>       @AlwaysCreatesNewInstances CacheFactory cacheFactory) {
>      this.underlyingFactory = cacheFactory;
>    }
>
>   @Override
>   NamedCache create(String name) {
>       return caches.get(name);
>   }
> }
>
>
> * * *
>
> public class YourModule extends AbstractModule {
>
>    @Override protected void configure() {
>        // as an alternative to binding this as a singleton, you could
> inject the map of caches
>        // as a singleton instance.  6 or 1/2 dozen, unless you want to
> unittest your
>        // implementation, in which case you'll want to inject the singleton
> map
>        bind(CacheFactory.class)
>            .to(CachingCacheFactory.class)
>            .in(Singleton.class);
>
>        //
> http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html
>        // this binds a "CacheFactory" instance, annotated with
> @AlwaysCreatesNewInstances, to
>        // a default factory implementation which will return instances of
> NamedCacheLocal when
>        // its create() method is invoked
>        install(new FactoryModuleBuilder()
>            .implement(NamedCache, NamedCacheLocal)
>            .build(Key.get(NamedCache.class,
> AlwaysCreatesNewInstances.class));
>     }
> }
>
> That should do the trick.
>
> -Fred
>
>
> On Thu, Oct 14, 2010 at 4:25 AM, Sondre Bjornebekk <
> sondre.bjorneb...@gmail.com> wrote:
>
>> Hi,
>>
>> Trying to use assisted inject and find it pretty neat, the minor
>> detail is that it does not quite work for me yet :-)
>>
>> I have created a Map wrapper to ease switching of caches (typically to
>> something like Coherence) for my application. I want the Map to be
>> returned "in a Singleton scope, based on the value of the (assisted)
>> parameter". I am doing:
>>
>> bind(CacheFactory.class).toProvider(
>> FactoryProvider.newFactory(CacheFactory.class,
>> NamedCacheLocal.class) );
>>
>> And I have:
>> /**
>>  * A factory for named caches, that later might hide its
>> implementation using a cluster wide storage.
>>  */
>>
>> public interface CacheFactory {
>>    //had to be named create to work with guice assisted inject, so
>> renamed from getNamedCache
>>    public NamedCache create(String name);
>> }
>>
>> public interface NamedCache<K,V> extends Map<K,V> {
>>    public int getHitPercent();
>>    public String getHitPercentString();
>>    ...
>> }
>>
>> /**
>>  * A named cache with a local map as implementation for storage.
>>  */
>>
>> public class NamedCacheLocal<K,V> implements NamedCache<K,V> {
>> ...
>>
>>    /**
>>     * Constructs a NamedCacheLocal with its dependencies.
>>     */
>>    @Inject
>>    public NamedCacheLocal(@Assisted String cacheName) {
>> ...
>> }
>>
>> I have this (failing) unit test that checks that the same cache is
>> used for the same name:
>>
>>        System.out.println("doing put / get test");
>>        NamedCache<String,String> namedCache =
>> namedCacheFactory.create("myCache");
>>        namedCache.put("fisk","fesk");
>>        for(int i=0;i<10; i++){
>>            Object o = namedCache.get("non-hit");
>>            namedCache.put("test"+i,"testval"+i);
>>        }
>>        Object hit = namedCache.get("fisk");
>>        System.out.println("cache " + namedCache + " delivered value "
>> + hit + " to a hit percent of " + namedCache.getHitPercentString());
>>        assertTrue(namedCache.getHitPercent() > 8 &&
>> namedCache.getHitPercent() < 10);
>>        NamedCache<String,String> namedCacheWithSameName =
>> namedCacheFactory.create("myCache");
>>        for(int i=0;i<10; i++){
>>            String val = namedCacheWithSameName.get("test"+i);
>>            System.out.println("got val from cache: " + val);
>>        }
>>        //should have used the same reference, thus hit pct now higher
>>        System.out.println("done with cache " +
>> namedCacheWithSameName);
>>        assertTrue(namedCache.getHitPercent() > 10);
>>        assertTrue(namedCache.equals(namedCacheWithSameName));
>>
>>
>> So is the thing I put in quotation marks in the intro ("in a Singleton
>> scope, based on the value of the (assisted) parameter") even possible
>> just by Guice config, or do I have to go two steps back and one
>> forward and just implement the CacheFactory myself with this logic?
>> The first thing I tried was
>>
>>        bind( CacheFactory.class ).
>>        toProvider( FactoryProvider.newFactory(CacheFactory.class,
>> NamedCacheLocal.class) ) .
>>        in ( Singleton.class );
>>
>> But that (of course) just gives me a singleton CacheFactory, not the
>> NamedCacheLocal "singleton" based on the assisted factory parameter.
>>
>> Cheers,
>>
>> Sondre
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "google-guice" group.
>> To post to this group, send email to google-gu...@googlegroups.com.
>> To unsubscribe from this group, send email to
>> google-guice+unsubscr...@googlegroups.com<google-guice%2bunsubscr...@googlegroups.com>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/google-guice?hl=en.
>>
>>
>  --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to google-gu...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-guice+unsubscr...@googlegroups.com<google-guice%2bunsubscr...@googlegroups.com>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>

-- 
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to google-gu...@googlegroups.com.
To unsubscribe from this group, send email to 
google-guice+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to