package it.mice.voila.runtime.security;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.MapBasedMethodSecurityMetadataSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

public abstract class ReloadableMethodSecurityMetadataSource extends
		MapBasedMethodSecurityMetadataSource implements InitializingBean {

	protected static Log logger = LogFactory.getLog(ReloadableMethodSecurityMetadataSource.class);
	
	@Autowired
	private ApplicationHolder applicationHolder;
	private String packagePrefix = "";
	
	public ApplicationHolder getApplicationHolder() {
		return applicationHolder;
	}

	public void setApplicationHolder(ApplicationHolder applicationHolder) {
		this.applicationHolder = applicationHolder;
	}

	public String getPackagePrefix() {
		return packagePrefix;
	}

	public void setPackagePrefix(String packagePrefix) {
		this.packagePrefix = packagePrefix;
	}

	public void afterPropertiesSet() throws Exception {
		reload();
	}

    /**
     * Add configuration attributes for a secure method. Method names can end or start with <code>&#42;</code>
     * for matching multiple methods.
     *
     * @param name type and method name, separated by a dot
     * @param attr the security attributes associated with the method
     */
    protected void addSecureMethod(String name, List<ConfigAttribute> attr) {
        int lastDotIndex = name.lastIndexOf(".");

        if (lastDotIndex == -1) {
            throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
        }

        String methodName = name.substring(lastDotIndex + 1);
        Assert.hasText(methodName, "Method not found for '" + name + "'");

        String typeName = name.substring(0, lastDotIndex);
        Class<?> type = ClassUtils.resolveClassName(typeName, ClassUtils.getDefaultClassLoader());

        addSecureMethod(type, methodName, attr);
    }

	protected abstract void reload();	
}
