/*
* This code is distributed under The GNU Lesser General Public License (LGPLv3)
* Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html
*
* Copyright Denis Pavlov 2009
* Web: http://www.genericdtoassembler.org
* SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/
* SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/
*/
package com.inspiresoftware.lib.dto.geda.interceptor.impl;
import com.inspiresoftware.lib.dto.geda.annotations.Occurrence;
import com.inspiresoftware.lib.dto.geda.interceptor.AdviceConfig;
import com.inspiresoftware.lib.dto.geda.interceptor.AdviceConfigResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Basic implementation of the resolved that examines method annotations in order to
* produce configuration objects. Provides method signature cache to store the
* configuration information in a permanent cache.
*
* Additionally this resolver keeps track of the methods that are not applicable and
* thus are blacklisted.
* <p/>
* User: denispavlov
* Date: Jan 26, 2012
* Time: 1:03:36 PM
*/
public class RuntimeAdviceConfigResolverImpl implements AdviceConfigResolver {
private static final Logger LOG = LoggerFactory.getLogger(RuntimeAdviceConfigResolverImpl.class);
private final Map<Integer, Boolean> blacklist = new ConcurrentHashMap<Integer, Boolean>();
private final Map<Integer, Map<Occurrence, AdviceConfig>> cache = new ConcurrentHashMap<Integer, Map<Occurrence, AdviceConfig>>();
public RuntimeAdviceConfigResolverImpl() {
}
/** {@inheritDoc} */
public Map<Occurrence, AdviceConfig> resolve(final Method method, final Class<?> targetClass) {
final Integer methodCacheKey = methodCacheKey(method, targetClass);
if (isBlacklisted(methodCacheKey)) {
return Collections.emptyMap();
}
if (isCached(methodCacheKey)) {
return this.cache.get(methodCacheKey);
}
final Map<Occurrence, AdviceConfig> cfg = resolveConfiguration(method, targetClass);
if (cfg.isEmpty()) {
this.blacklist.put(methodCacheKey, Boolean.TRUE);
} else {
cache.put(methodCacheKey, cfg);
if (LOG.isInfoEnabled()) {
LOG.info("Added GeDA configuration for method: {}.{}[p={}]... {} total mappings so far",
new Object[] {
targetClass == null ? method.getDeclaringClass().getCanonicalName() : targetClass.getCanonicalName(),
method.getName(),
method.getParameterTypes().length,
cache.size() });
}
}
return cfg;
}
boolean isCached(final Integer methodCacheKey) {
return this.cache.containsKey(methodCacheKey);
}
boolean isBlacklisted(final Integer methodCacheKey) {
return this.blacklist.containsKey(methodCacheKey);
}
Map<Occurrence, AdviceConfig> resolveConfiguration(final Method method,
final Class<?> targetClass) {
return TransferableUtils.resolveConfiguration(method, targetClass);
}
Integer methodCacheKey(final Method method, final Class<?> targetClass) {
int hashKey = targetClass != null ? targetClass.getCanonicalName().hashCode() : method.getDeclaringClass().getCanonicalName().hashCode();
hashKey = 31 * hashKey + method.getName().hashCode();
final Class[] args = method.getParameterTypes();
if (args.length > 0) {
for (Class arg : args) {
hashKey = 31 * hashKey + arg.hashCode();
}
}
return Integer.valueOf(hashKey);
}
}