/**
  * {@inheritDoc}
  *
  * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
  */
 public Collection<ConfigAttribute> getAllConfigAttributes() {
   Set<ConfigAttribute> set = new HashSet<ConfigAttribute>();
   for (MethodSecurityMetadataSource s : _methodSecurityMetadataSources) {
     Collection<ConfigAttribute> attrs = s.getAllConfigAttributes();
     if (attrs != null) {
       set.addAll(attrs);
     }
   }
   return set;
 }
  /**
   * {@inheritDoc}
   *
   * @see org.springframework.security.access.method.MethodSecurityMetadataSource#getAttributes(
   *     java.lang.reflect.Method, java.lang.Class)
   */
  public Collection<ConfigAttribute> getAttributes(final Method m, final Class<?> tc) {

    Method method = ProxyUtils.unproxy(m);
    Class<?> targetClass = ProxyUtils.unproxy(tc);

    DefaultCacheKey cacheKey = new DefaultCacheKey(method, targetClass);
    synchronized (_cache) {
      Collection<ConfigAttribute> cached = _cache.get(cacheKey);
      // Check for canonical value indicating there is no config attribute,
      if (cached == NULL_CONFIG_ATTRIBUTE) {
        return null;
      }

      if (cached != null) {
        return cached;
      }

      // No cached value, so query the sources to find a result
      Collection<ConfigAttribute> attributes = null;
      for (MethodSecurityMetadataSource s : _methodSecurityMetadataSources) {
        attributes = s.getAttributes(method, targetClass);
        if (attributes != null && !attributes.isEmpty()) {
          break;
        }
      }

      // Put it in the cache.
      if (attributes == null) {
        _cache.put(cacheKey, NULL_CONFIG_ATTRIBUTE);
        return null;
      }

      if (logger.isDebugEnabled()) {
        logger.debug("Adding security method [" + cacheKey + "] with attributes " + attributes);
      }

      _cache.put(cacheKey, attributes);

      return attributes;
    }
  }