mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18931 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
			
				
	
	
		
			254 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2005-2010 Alfresco Software Limited.
 | 
						|
 *
 | 
						|
 * This file is part of Alfresco
 | 
						|
 *
 | 
						|
 * Alfresco is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU Lesser General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * Alfresco is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU Lesser General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public License
 | 
						|
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
package org.alfresco.repo.policy;
 | 
						|
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Collection;
 | 
						|
import java.util.HashMap;
 | 
						|
import java.util.Map;
 | 
						|
import java.util.concurrent.locks.ReentrantReadWriteLock;
 | 
						|
 | 
						|
import org.apache.commons.logging.Log;
 | 
						|
import org.apache.commons.logging.LogFactory;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Policy Factory with caching support.
 | 
						|
 *
 | 
						|
 * @author David Caruana
 | 
						|
 *
 | 
						|
 * @param <B>  the type of Binding
 | 
						|
 * @param <P>  the type of Policy
 | 
						|
 */
 | 
						|
/*package*/ class CachedPolicyFactory<B extends BehaviourBinding, P extends Policy> extends PolicyFactory<B, P> 
 | 
						|
{
 | 
						|
    // Logger
 | 
						|
    private static final Log logger = LogFactory.getLog(PolicyComponentImpl.class);
 | 
						|
 | 
						|
    // Behaviour Filter
 | 
						|
    private BehaviourFilter behaviourFilter = null;
 | 
						|
    
 | 
						|
    // Cache Lock
 | 
						|
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 
 | 
						|
 | 
						|
    /**
 | 
						|
     * Cache for a single Policy interface (keyed by Binding)
 | 
						|
     */
 | 
						|
    private Map<B, P> singleCache = new HashMap<B, P>();
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Cache for a collection of Policy interfaces (keyed by Binding)
 | 
						|
     */
 | 
						|
    private Map<B, Collection<P>> listCache = new HashMap<B, Collection<P>>();
 | 
						|
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Construct cached policy factory
 | 
						|
     * 
 | 
						|
     * @param policyClass  the policy interface class
 | 
						|
     * @param index  the behaviour index to search on
 | 
						|
     */
 | 
						|
    /*package*/ CachedPolicyFactory(Class<P> policyClass, BehaviourIndex<B> index)
 | 
						|
    {
 | 
						|
        super(policyClass, index);
 | 
						|
        behaviourFilter = index.getFilter();
 | 
						|
 | 
						|
        // Register this cached policy factory as a change observer of the behaviour index
 | 
						|
        // to allow for cache to be cleared appropriately.
 | 
						|
        index.addChangeObserver(new BehaviourChangeObserver<B>()
 | 
						|
        {
 | 
						|
            public void addition(B binding, Behaviour behaviour)
 | 
						|
            {
 | 
						|
                clearCache("aggregate delegate", singleCache, binding);
 | 
						|
                clearCache("delegate collection", listCache, binding);
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    @Override
 | 
						|
    public P create(B binding)
 | 
						|
    {
 | 
						|
        // When behaviour filters are activated bypass the cache 
 | 
						|
        if (behaviourFilter != null && behaviourFilter.isActivated())
 | 
						|
        {
 | 
						|
            return super.create(binding);
 | 
						|
        }
 | 
						|
        
 | 
						|
        lock.readLock().lock();
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            P policyInterface = singleCache.get(binding);
 | 
						|
            if (policyInterface == null)
 | 
						|
            {
 | 
						|
                // Upgrade read lock to write lock
 | 
						|
                lock.readLock().unlock();
 | 
						|
                lock.writeLock().lock();
 | 
						|
 | 
						|
                try
 | 
						|
                {
 | 
						|
                    // Check again
 | 
						|
                    policyInterface = singleCache.get(binding);
 | 
						|
                    if (policyInterface == null)
 | 
						|
                    {
 | 
						|
                        policyInterface = super.create(binding);
 | 
						|
                        singleCache.put(binding, policyInterface);
 | 
						|
                        
 | 
						|
                        if (logger.isDebugEnabled())
 | 
						|
                            logger.debug("Cached delegate interface " + policyInterface + " for " + binding + " and policy " + getPolicyClass());
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                finally
 | 
						|
                {
 | 
						|
                    // Downgrade lock to read
 | 
						|
                    lock.readLock().lock();
 | 
						|
                    lock.writeLock().unlock();
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return policyInterface;
 | 
						|
        }
 | 
						|
        finally
 | 
						|
        {
 | 
						|
            lock.readLock().unlock();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
 | 
						|
    @Override
 | 
						|
    public Collection<P> createList(B binding)
 | 
						|
    {
 | 
						|
        // When behaviour filters are activated bypass the cache 
 | 
						|
        if (behaviourFilter != null && behaviourFilter.isActivated())
 | 
						|
        {
 | 
						|
            return super.createList(binding);
 | 
						|
        }
 | 
						|
        
 | 
						|
        lock.readLock().lock();
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            Collection<P> policyInterfaces = listCache.get(binding);
 | 
						|
            if (policyInterfaces == null)
 | 
						|
            {
 | 
						|
                // Upgrade read lock to write lock
 | 
						|
                lock.readLock().unlock();
 | 
						|
                lock.writeLock().lock();
 | 
						|
 | 
						|
                try
 | 
						|
                {
 | 
						|
                    // Check again
 | 
						|
                    policyInterfaces = listCache.get(binding);
 | 
						|
                    if (policyInterfaces == null)
 | 
						|
                    {                
 | 
						|
                        policyInterfaces = super.createList(binding);
 | 
						|
                        listCache.put(binding, policyInterfaces);
 | 
						|
                
 | 
						|
                        if (logger.isDebugEnabled())
 | 
						|
                            logger.debug("Cached delegate interface collection " + policyInterfaces + " for " + binding + " and policy " + getPolicyClass());
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                finally
 | 
						|
                {
 | 
						|
                    // Downgrade lock to read
 | 
						|
                    lock.readLock().lock();
 | 
						|
                    lock.writeLock().unlock();
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return policyInterfaces;
 | 
						|
        }                
 | 
						|
        finally
 | 
						|
        {
 | 
						|
            lock.readLock().unlock();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Clear entries in the cache based on binding changes.
 | 
						|
     * 
 | 
						|
     * @param cacheDescription  description of cache to clear
 | 
						|
     * @param cache  the cache to clear
 | 
						|
     * @param binding  the binding
 | 
						|
     */
 | 
						|
    private void clearCache(String cacheDescription, Map<B, ?> cache, B binding)
 | 
						|
    {
 | 
						|
        if (binding == null)
 | 
						|
        {
 | 
						|
            lock.writeLock().lock();
 | 
						|
 | 
						|
            try
 | 
						|
            {
 | 
						|
                // A specific binding has not been provided, so clear all entries
 | 
						|
                cache.clear();
 | 
						|
                
 | 
						|
                if (logger.isDebugEnabled() && cache.isEmpty() == false)
 | 
						|
                    logger.debug("Cleared " + cacheDescription + " cache (all class bindings) for policy " + getPolicyClass());
 | 
						|
            }
 | 
						|
            finally
 | 
						|
            {
 | 
						|
                lock.writeLock().unlock();
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            // A specific binding has been provided.  Build a list of entries
 | 
						|
            // that require removal.  An entry is removed if the binding in the
 | 
						|
            // list is equal or derived from the changed binding. 
 | 
						|
            Collection<B> invalidBindings = new ArrayList<B>();
 | 
						|
            for (B cachedBinding : cache.keySet())
 | 
						|
            {
 | 
						|
                // Determine if binding is equal or derived from changed binding
 | 
						|
                BehaviourBinding generalisedBinding = cachedBinding;
 | 
						|
                while(generalisedBinding != null)
 | 
						|
                {
 | 
						|
                    if (generalisedBinding.equals(binding))
 | 
						|
                    {
 | 
						|
                        invalidBindings.add(cachedBinding);
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                    generalisedBinding = generalisedBinding.generaliseBinding();
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            // Remove all invalid bindings
 | 
						|
            if (invalidBindings.size() > 0)
 | 
						|
            {
 | 
						|
                lock.writeLock().lock();
 | 
						|
                
 | 
						|
                try
 | 
						|
                {
 | 
						|
                    for (B invalidBinding : invalidBindings)
 | 
						|
                    {
 | 
						|
                        cache.remove(invalidBinding);
 | 
						|
                        
 | 
						|
                        if (logger.isDebugEnabled())
 | 
						|
                            logger.debug("Cleared " + cacheDescription + " cache for " + invalidBinding + " and policy " + getPolicyClass());
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                finally
 | 
						|
                {
 | 
						|
                    lock.writeLock().unlock();
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
}
 |