dinesh94 / simple-spring-memcached

Automatically exported from code.google.com/p/simple-spring-memcached
MIT License
0 stars 0 forks source link

more fexibility with CacheKeyMethod and key generation #14

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
CacheKeyMethod can only be set on one method of the object. if you want the key 
constructed from a few fields you have to write your own method to build the 
key. 
so adding ability to set CacheKeyMethod on more then one method and maybe add 
an order parameter.
also the return must be string which is limiting , can just use the toString of 
return values.

IMP using CacheKeyMethod in some cases is bad design, to add cache knowledge 
and specific methods to classes. in my case the objects are hibernate entities 
and I don't want to fill them with cache knowledge and to couple them with SSM.
could add a keyGeneratorClass parameter to all ReadThrough* annotations and 
invoke it with the annotation data and method data to generate the key.

Original issue reported on code.google.com by shalom...@gmail.com on 18 Mar 2013 at 2:35

GoogleCodeExporter commented 9 years ago
Adding a keyGeneratorClass is a good idea. How do you want to use it with 
ReadThrough* annotations? Could you show some examples how intercepted method 
should work with keyGeneratorClass and ReadThrough*?

Original comment by ragno...@gmail.com on 18 Mar 2013 at 10:06

GoogleCodeExporter commented 9 years ago
This is my current code where I added a generateCacheKey method on 
PermittedEntity and marked it with @CacheKeyMethod

@ReadThroughSingleCache(namespace = RE_CACHE_NS,expiration = 36000)
public Set<Group> getRepresentativeEntities(@ParameterValueKeyProvider(order = 
1) PermittedEntity entity, @ParameterValueKeyProvider(order = 2) boolean 
inherit){
...
}

I prefer not coupling PermittedEntity with SSM and not adding this kind of code 
to many of my entities. I'd like to do something like that:

@ReadThroughSingleCache(namespace = RE_CACHE_NS,expiration = 36000,keyGenerator 
= PermittedEntityKeyGenerator.class)
public Set<Group> getRepresentativeEntities(@ParameterValueKeyProvider(order = 
1) PermittedEntity entity, @ParameterValueKeyProvider(order = 2) boolean 
inherit)

public class PermittedEntityKeyGenerator{
//where key providers are the arguments marked with @ParameterValueKeyProvider
@CacheKeyMethod
public String generateCacheKey(Object[] keyProviders){
...
}

}

or generateCacheKey could just have the same signature as getCacheKey in 
SingleReadCacheAdvice:
String getCacheKey(final AnnotationData data, final Object[] args, final String 
methodDesc)

and if there is a keyGenerator use it, else do it as before.

Original comment by shalom...@gmail.com on 19 Mar 2013 at 8:55

GoogleCodeExporter commented 9 years ago
As I understand you don't want to use keyGenerator on cached class/entity but 
on some other class used as a ParameterValueKeyProvider, do you?

Original comment by ragno...@gmail.com on 19 Mar 2013 at 6:14

GoogleCodeExporter commented 9 years ago
Currently it is possible to create custom 
com.google.code.ssm.aop.support.CacheKeyBuilder and use it instead of the 
default one (CacheKeyBuilderImpl).
In your case you can extend CacheKeyBuilderImpl and if the methodDesc matches 
to some pattern (or one of the args is of given type) instead of default logic 
execute own code to created cache key. 
Does it suit you?

Original comment by ragno...@gmail.com on 19 Mar 2013 at 6:23

GoogleCodeExporter commented 9 years ago
Thanks. CacheKeyBuilder is a good option and I did implement it and removed 
CacheKeyMethod from my entities.IMO its a better option.
still, it brings worries with it, needs maintenance and to preserve 
compatibility with future SSM versions. where supplying a hook on a per method 
basis is simpler to implement and is not coupled with SSM.
In order to replace CacheKeyBuilder I also had to override cacheBase bean 
imported from your simplesm-context.xml and I'm relying on spring to override 
it. 

anyway, for references to others, this is my implementation, I did copy paste 
your private buildCacheKey method and used DefaultKeyProvider in my code.

    @Override
    public String getCacheKey(AnnotationData data, Object[] args, String methodDesc) throws Exception
    {
        final Object[] keysObjects = Utils.getMethodArgs(data.getKeyIndexes(), args, methodDesc);

        if (keysObjects == null || keysObjects.length < 1) {
            throw new InvalidParameterException("At least one key provider object needed for cached method.");
        }

        if (contains(SdAbstractEntity.class, keysObjects) || contains(ADPojoBase.class, keysObjects)){
            return getSpecialCacheKey(data, keysObjects);
        }else{
            return super.getCacheKey(data, args, methodDesc);
        }
    }

    private String getSpecialCacheKey(AnnotationData data, Object[] keysObjects)
    {
        List<String> keyParts = new ArrayList<String>();
        for (Object keyProvider: keysObjects){
            if (SdPermittedEntity.class.isAssignableFrom(keyProvider.getClass())){
                keyParts.add(getSdPermittedEntityKey((SdPermittedEntity)keyProvider));
            }else if (SdAbstractEntity.class.isAssignableFrom(keyProvider.getClass())){
                keyParts.add(getSdAbstractEntityKey((SdAbstractEntity) keyProvider));
            }else if (ADPojoBase.class.isAssignableFrom(keyProvider.getClass())){
                keyParts.add(getADPojoBaseKey((ADPojoBase)keyProvider));
            }else{
                keyParts.add(defaultKeyProvider.generateKey(keyProvider));
            }

        }

        final String[] objectKeys = keyParts.toArray(new String[keyParts.size()]);

        return buildCacheKey(objectKeys, data.getNamespace());
    }

Thank you.

Original comment by shalom...@gmail.com on 20 Mar 2013 at 12:37

GoogleCodeExporter commented 9 years ago
Well , after noticing that I don't support multi cache keys in my 
CacheKeyBuilder I realized that I can replace only the DefaultKeyProvider to 
support my special keys instead of replacing CacheKeyBuilder, and its good for 
all cache aspects.  so now I use CacheKeyBuilderImpl with my own KeyProvider, I 
had to override only generateKey.
this is now very satisfying for me.

   @Override
    public String generateKey(Object keyObject)
    {
        if (SdPermittedEntity.class.isAssignableFrom(keyObject.getClass()))
        {
            keyObject = getSdPermittedEntityKey((SdPermittedEntity) keyObject);
        } else if (SdAbstractEntity.class.isAssignableFrom(keyObject.getClass()))
        {
            keyObject = getSdAbstractEntityKey((SdAbstractEntity) keyObject);
        } else if (ADPojoBase.class.isAssignableFrom(keyObject.getClass()))
        {
            keyObject = getADPojoBaseKey((ADPojoBase) keyObject);
        }

        return super.generateKey(keyObject);
    }

Original comment by shalom...@gmail.com on 20 Mar 2013 at 6:20

GoogleCodeExporter commented 9 years ago
So may I close the issue or do you still would like to see keyGenerator in next 
SSM release?

Original comment by ragno...@gmail.com on 20 Mar 2013 at 6:30

GoogleCodeExporter commented 9 years ago
Sure, you can close. I'm doing fine as it is now. Thanks for your help.

Original comment by shalom...@gmail.com on 20 Mar 2013 at 6:39

GoogleCodeExporter commented 9 years ago
No problem.

Original comment by ragno...@gmail.com on 20 Mar 2013 at 6:42