/* * 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.AdviceConfigRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * . * <p/> * User: denispavlov * Date: Jan 27, 2012 * Time: 4:44:13 PM */ public class AdviceConfigRepositoryImpl implements AdviceConfigRepository { private static final Logger LOG = LoggerFactory.getLogger(AdviceConfigRepositoryImpl.class); private final Map<String, Map<Integer, Map<Occurrence, AdviceConfig>>> cache = new ConcurrentHashMap<String, Map<Integer, Map<Occurrence, AdviceConfig>>>(); /** {@inheritDoc} */ public void addApplicableMethods(final Object bean) { final Method[] methods = bean.getClass().getMethods(); for (final Method method : methods) { if (Modifier.isPublic(method.getModifiers())) { addMethodIfApplicable(method, bean.getClass()); } } } public void addMethodIfApplicable(final Method method, final Class<?> targetClass) { Map<Integer, Map<Occurrence, AdviceConfig>> cMap = getAdvisableMethodsConfigurations(targetClass); if (cMap.isEmpty()) { cMap = new ConcurrentHashMap<Integer, Map<Occurrence, AdviceConfig>>(); cache.put(targetClass.getCanonicalName(), cMap); } final Integer key = methodCacheKey(method, targetClass); if (!cMap.containsKey(key)) { final Map<Occurrence, AdviceConfig> methodCfg = resolveConfiguration(method, targetClass); if (methodCfg.isEmpty()) { return; } cMap.put(key, methodCfg); if (LOG.isInfoEnabled()) { int methCount = 0; for (Map meths : cache.values()) { methCount += meths.size(); } LOG.info("Added GeDA configuration for method: {}.{}[p={}]... {} total mappings so far", new Object[] { targetClass.getCanonicalName(), method.getName(), method.getParameterTypes().length, methCount }); } } } Map<Occurrence, AdviceConfig> resolveConfiguration(final Method method, final Class<?> targetClass) { return TransferableUtils.resolveConfiguration(method, targetClass); } /** {@inheritDoc} */ public Map<Integer, Map<Occurrence, AdviceConfig>> getAdvisableMethodsConfigurations(final Class<?> targetClass) { if (targetClass == null) { return Collections.emptyMap(); } final Map<Integer, Map<Occurrence, AdviceConfig>> cMap = cache.get(targetClass.getCanonicalName()); if (cMap == null) { return Collections.emptyMap(); } return cMap; } /** * This key generation algorithm uses plain java.lang.reflect.Method.toString() to create a * unique method signature that can be used. * * @param method potentially advisable method * @param targetClass bean class on which it is invoked * @return key for this method/class pair */ public Integer methodCacheKey(final Method method, final Class<?> targetClass) { final StringBuilder signature = new StringBuilder(method.getName()).append('('); final Class[] args = method.getParameterTypes(); if (args.length > 0) { for (Class arg : args) { signature.append(arg.getCanonicalName()).append(','); } signature.deleteCharAt(signature.length() - 1); } signature.append(')'); return signature.toString().hashCode(); /* int 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); */ } }