mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	19246: ALF-1940 - case-insensitive AVM path lookups fail on a DB that is (configured by default to be) case-sensitive
    19280: AVM - preserve case on child lookup, add unit tests
    19316: AVM - fix rename (change in 'case') & add unit tests (ALF-1725 & ALF-1767)
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@19337 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
	
		
			
				
	
	
		
			556 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			556 lines
		
	
	
		
			20 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.domain.avm;
 | 
						|
 | 
						|
import java.io.Serializable;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.List;
 | 
						|
 | 
						|
import org.alfresco.repo.cache.SimpleCache;
 | 
						|
import org.alfresco.repo.cache.lookup.EntityLookupCache;
 | 
						|
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO;
 | 
						|
import org.alfresco.util.Pair;
 | 
						|
import org.springframework.extensions.surf.util.ParameterCheck;
 | 
						|
import org.alfresco.util.SearchLanguageConversion;
 | 
						|
import org.springframework.dao.ConcurrencyFailureException;
 | 
						|
 | 
						|
/**
 | 
						|
 * Abstract implementation for AVMNodeLinks DAO.
 | 
						|
 * <p>
 | 
						|
 * This provides basic services such as caching but defers to the underlying implementation
 | 
						|
 * for CRUD operations.
 | 
						|
 * 
 | 
						|
 * @author janv
 | 
						|
 * @since 3.2
 | 
						|
 */
 | 
						|
public abstract class AbstractAVMNodeLinksDAOImpl implements AVMNodeLinksDAO
 | 
						|
{
 | 
						|
    private static final String CACHE_REGION_AVM_CHILD_ENTRY = "AVMChildEntry";
 | 
						|
    private static final String CACHE_REGION_AVM_HISTORY_LINK = "AVMHistoryLink";
 | 
						|
    
 | 
						|
    private final AVMChildEntryEntityCallbackDAO avmChildEntryEntityDaoCallback;
 | 
						|
    private final AVMHistoryLinkEntityCallbackDAO avmHistoryLinkEntityDaoCallback;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Cache for the AVM child entry entity:<br/>
 | 
						|
     * KEY: ChildKey<br/>
 | 
						|
     * VALUE: AVMChildEntryEntity<br/>
 | 
						|
     * VALUE KEY: Pair of node IDs (parent, child)<br/>
 | 
						|
     */
 | 
						|
    private EntityLookupCache<ChildKey, AVMChildEntryEntity, Pair<Long, Long>> avmChildEntryCache;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Cache for the AVM history link entity:<br/>
 | 
						|
     * KEY: Descendent ID<br/>
 | 
						|
     * VALUE: AVMHistoryLinkEntity<br/>
 | 
						|
     * VALUE KEY: AVMHistoryLinkEntity<br/>
 | 
						|
     */
 | 
						|
    private EntityLookupCache<Long, AVMHistoryLinkEntity, AVMHistoryLinkEntity> avmHistoryLinkCache;
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Set the cache to use for <b>avm_child_entry</b> lookups (optional).
 | 
						|
     * 
 | 
						|
     * @param avmChildEntryCache            the cache of IDs to AVMChildEntryEntities
 | 
						|
     */
 | 
						|
    public void setAvmChildEntryCache(SimpleCache<Serializable, Object> avmChildEntryCache)
 | 
						|
    {
 | 
						|
        this.avmChildEntryCache = new EntityLookupCache<ChildKey, AVMChildEntryEntity, Pair<Long, Long>>(
 | 
						|
                avmChildEntryCache,
 | 
						|
                CACHE_REGION_AVM_CHILD_ENTRY,
 | 
						|
                avmChildEntryEntityDaoCallback);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Set the cache to use for <b>avm_history_link</b> lookups (optional).
 | 
						|
     * 
 | 
						|
     * @param avmHistoryLinkCache            the cache of ID to ID (from descendent to ancestor)
 | 
						|
     */
 | 
						|
    public void setAvmHistoryLinkCache(SimpleCache<Serializable, Object> avmHistoryLinkCache)
 | 
						|
    {
 | 
						|
        this.avmHistoryLinkCache = new EntityLookupCache<Long, AVMHistoryLinkEntity, AVMHistoryLinkEntity>(
 | 
						|
                avmHistoryLinkCache,
 | 
						|
                CACHE_REGION_AVM_HISTORY_LINK,
 | 
						|
                avmHistoryLinkEntityDaoCallback);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Default constructor.
 | 
						|
     * <p>
 | 
						|
     * This sets up the DAO accessors to bypass any caching to handle the case where the caches are not
 | 
						|
     * supplied in the setters.
 | 
						|
     */
 | 
						|
    public AbstractAVMNodeLinksDAOImpl()
 | 
						|
    {
 | 
						|
        this.avmChildEntryEntityDaoCallback = new AVMChildEntryEntityCallbackDAO();
 | 
						|
        this.avmChildEntryCache = new EntityLookupCache<ChildKey, AVMChildEntryEntity, Pair<Long, Long>>(avmChildEntryEntityDaoCallback);
 | 
						|
        
 | 
						|
        this.avmHistoryLinkEntityDaoCallback = new AVMHistoryLinkEntityCallbackDAO();
 | 
						|
        this.avmHistoryLinkCache = new EntityLookupCache<Long, AVMHistoryLinkEntity, AVMHistoryLinkEntity>(avmHistoryLinkEntityDaoCallback);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void createChildEntry(long parentNodeId, String name, long childNodeId)
 | 
						|
    {
 | 
						|
        ParameterCheck.mandatory("name", name);
 | 
						|
        
 | 
						|
        AVMChildEntryEntity ceEntity = new AVMChildEntryEntity();
 | 
						|
        ceEntity.setParentNodeId(parentNodeId);
 | 
						|
        ceEntity.setName(name);
 | 
						|
        ceEntity.setChildNodeId(childNodeId);
 | 
						|
        
 | 
						|
        Pair<ChildKey, AVMChildEntryEntity> entityPair = avmChildEntryCache.getOrCreateByValue(ceEntity);
 | 
						|
        entityPair.getSecond();
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public AVMChildEntryEntity getChildEntry(long parentNodeId, String name)
 | 
						|
    {
 | 
						|
        ParameterCheck.mandatory("name", name);
 | 
						|
        
 | 
						|
        Pair<ChildKey, AVMChildEntryEntity> entityPair = avmChildEntryCache.getByKey(new ChildKey(parentNodeId, name));
 | 
						|
        if (entityPair == null)
 | 
						|
        {
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
        return entityPair.getSecond();
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public List<AVMChildEntryEntity> getChildEntriesByParent(long parentNodeId, String childNamePattern)
 | 
						|
    {
 | 
						|
        List<AVMChildEntryEntity> result = null;
 | 
						|
        
 | 
						|
        if ((childNamePattern == null) || (childNamePattern.length() == 0))
 | 
						|
        {
 | 
						|
            result = getChildEntryEntitiesByParent(parentNodeId);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            String pattern = SearchLanguageConversion.convert(SearchLanguageConversion.DEF_LUCENE, SearchLanguageConversion.DEF_SQL_LIKE, childNamePattern);
 | 
						|
            result = getChildEntryEntitiesByParent(parentNodeId, pattern);
 | 
						|
        }
 | 
						|
        
 | 
						|
        if (result == null)
 | 
						|
        {
 | 
						|
            result = new ArrayList<AVMChildEntryEntity>(0);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public AVMChildEntryEntity getChildEntry(long parentNodeId, long childNodeId)
 | 
						|
    {
 | 
						|
        AVMChildEntryEntity ceEntity = new AVMChildEntryEntity();
 | 
						|
        ceEntity.setParentNodeId(parentNodeId);
 | 
						|
        ceEntity.setChildNodeId(childNodeId);
 | 
						|
        
 | 
						|
        Pair<ChildKey, AVMChildEntryEntity> entityPair = avmChildEntryCache.getByValue(ceEntity);
 | 
						|
        if (entityPair == null)
 | 
						|
        {
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
        return entityPair.getSecond();
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public List<AVMChildEntryEntity> getChildEntriesByChild(long childNodeId)
 | 
						|
    {
 | 
						|
        List<AVMChildEntryEntity> result = getChildEntryEntitiesByChild(childNodeId);
 | 
						|
        if (result == null)
 | 
						|
        {
 | 
						|
            result = new ArrayList<AVMChildEntryEntity>(0);
 | 
						|
        }
 | 
						|
        
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void updateChildEntry(AVMChildEntryEntity childEntryEntity)
 | 
						|
    {
 | 
						|
        ParameterCheck.mandatory("childEntryEntity", childEntryEntity);
 | 
						|
        ParameterCheck.mandatory("childEntryEntity.getParentNodeId()", childEntryEntity.getParentNodeId());
 | 
						|
        ParameterCheck.mandatory("childEntryEntity.getChildId()", childEntryEntity.getChildId());
 | 
						|
        ParameterCheck.mandatory("childEntryEntity.getName()", childEntryEntity.getName());
 | 
						|
        
 | 
						|
        ChildKey key = new ChildKey(childEntryEntity.getParentNodeId(), childEntryEntity.getName());
 | 
						|
        int updated = avmChildEntryCache.updateValue(key, childEntryEntity);
 | 
						|
        if (updated < 1)
 | 
						|
        {
 | 
						|
            throw new ConcurrencyFailureException("AVMChildEntry for parent/name (" + key.getParentNodeId() + ", " + key.getName() + ") no longer exists");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void deleteChildEntry(AVMChildEntryEntity childEntryEntity)
 | 
						|
    {
 | 
						|
        ParameterCheck.mandatory("childEntryEntity", childEntryEntity);
 | 
						|
        
 | 
						|
        ParameterCheck.mandatory("childEntryEntity.getParentNodeId()", childEntryEntity.getParentNodeId());
 | 
						|
        ParameterCheck.mandatory("childEntryEntity.getName()", childEntryEntity.getName());
 | 
						|
        
 | 
						|
        ChildKey key = new ChildKey(childEntryEntity.getParentNodeId(), childEntryEntity.getName());
 | 
						|
        Pair<ChildKey, AVMChildEntryEntity> entityPair = avmChildEntryCache.getByKey(key);
 | 
						|
        if (entityPair == null)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        int deleted = avmChildEntryCache.deleteByKey(key);
 | 
						|
        if (deleted < 1)
 | 
						|
        {
 | 
						|
            throw new ConcurrencyFailureException("AVMChildEntry for parent/name (" + key.getParentNodeId() + ", " + key.getName() + ") no longer exists");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void deleteChildEntriesByParent(long parentNodeId)
 | 
						|
    {
 | 
						|
        List<AVMChildEntryEntity> ceEntities = getChildEntriesByParent(parentNodeId, null);
 | 
						|
        if (ceEntities.size() == 0)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        for (AVMChildEntryEntity ceEntity : ceEntities)
 | 
						|
        {
 | 
						|
            deleteChildEntry(ceEntity);
 | 
						|
        }
 | 
						|
        
 | 
						|
        // TODO single delete + cache(s)
 | 
						|
        
 | 
						|
        /*
 | 
						|
        int deleted = deleteChildEntryEntities(parentNodeId);
 | 
						|
        if (deleted < 1)
 | 
						|
        {
 | 
						|
            throw new ConcurrencyFailureException("AVMChildEntries for parent node ID " + parentNodeId + " no longer exist");
 | 
						|
        }
 | 
						|
        
 | 
						|
        // TODO clear child entry cache for this parent node id
 | 
						|
        */
 | 
						|
    }
 | 
						|
    
 | 
						|
    private static class ChildKey implements Serializable
 | 
						|
    {
 | 
						|
        private static final long serialVersionUID = 848161072437569305L;
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * The Parent Node Id
 | 
						|
         */
 | 
						|
        private Long parentNodeId;
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * The child's name.
 | 
						|
         */
 | 
						|
        private String name;
 | 
						|
        
 | 
						|
        public ChildKey(Long parentNodeId, String name)
 | 
						|
        {
 | 
						|
            this.parentNodeId = parentNodeId;
 | 
						|
            this.name = name;
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Long getParentNodeId()
 | 
						|
        {
 | 
						|
            return parentNodeId;
 | 
						|
        }
 | 
						|
        
 | 
						|
        public String getName()
 | 
						|
        {
 | 
						|
            return name;
 | 
						|
        }
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * Override of equals.
 | 
						|
         */
 | 
						|
        @Override
 | 
						|
        public boolean equals(Object other)
 | 
						|
        {
 | 
						|
            if (this == other)
 | 
						|
            {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            if (!(other instanceof ChildKey))
 | 
						|
            {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
            ChildKey o = (ChildKey)other;
 | 
						|
            return parentNodeId.equals(o.getParentNodeId()) &&
 | 
						|
                   name.equalsIgnoreCase(o.getName());
 | 
						|
        }
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * Override of hashCode.
 | 
						|
         */
 | 
						|
        public int hashCode()
 | 
						|
        {
 | 
						|
            return parentNodeId.hashCode() + name.toLowerCase().hashCode();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Callback for <b>avm_child_entry</b> DAO
 | 
						|
     */
 | 
						|
    private class AVMChildEntryEntityCallbackDAO implements EntityLookupCallbackDAO<ChildKey, AVMChildEntryEntity, Pair<Long, Long>>
 | 
						|
    {
 | 
						|
        private final Pair<ChildKey, AVMChildEntryEntity> convertEntityToPair(AVMChildEntryEntity ceEntity)
 | 
						|
        {
 | 
						|
            if (ceEntity == null)
 | 
						|
            {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return new Pair<ChildKey, AVMChildEntryEntity>(new ChildKey(ceEntity.getParentNodeId(), ceEntity.getName()), ceEntity);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<Long, Long> getValueKey(AVMChildEntryEntity value)
 | 
						|
        {
 | 
						|
            return new Pair<Long,Long>(value.getParentNodeId(), value.getChildId());
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<ChildKey, AVMChildEntryEntity> createValue(AVMChildEntryEntity value)
 | 
						|
        {
 | 
						|
            createChildEntryEntity(value);
 | 
						|
            return convertEntityToPair(value);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<ChildKey, AVMChildEntryEntity> findByKey(ChildKey key)
 | 
						|
        {
 | 
						|
            AVMChildEntryEntity entity = getChildEntryEntity(key.getParentNodeId(), key.getName());
 | 
						|
            return convertEntityToPair(entity);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<ChildKey, AVMChildEntryEntity> findByValue(AVMChildEntryEntity value)
 | 
						|
        {
 | 
						|
            AVMChildEntryEntity entity = getChildEntryEntity(value.getParentNodeId(), value.getChildId());
 | 
						|
            return convertEntityToPair(entity);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int updateValue(ChildKey key, AVMChildEntryEntity value)
 | 
						|
        {
 | 
						|
            return updateChildEntryEntity(value);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int deleteByKey(ChildKey key)
 | 
						|
        {
 | 
						|
            return deleteChildEntryEntity(key.getParentNodeId(), key.getName());
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int deleteByValue(AVMChildEntryEntity value)
 | 
						|
        {
 | 
						|
            return deleteChildEntryEntity(value.getParentNodeId(), value.getChildId());
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    protected abstract List<AVMChildEntryEntity> getChildEntryEntitiesByParent(long parentNodeId);
 | 
						|
    protected abstract List<AVMChildEntryEntity> getChildEntryEntitiesByParent(long parentNodeId, String childNamePattern);
 | 
						|
    protected abstract List<AVMChildEntryEntity> getChildEntryEntitiesByChild(long childNodeId);
 | 
						|
    
 | 
						|
    protected abstract AVMChildEntryEntity getChildEntryEntity(long parentNodeId, String name);
 | 
						|
    protected abstract AVMChildEntryEntity getChildEntryEntity(long parentNodeId, long childNodeId);
 | 
						|
    protected abstract AVMChildEntryEntity getChildEntryEntity(AVMChildEntryEntity childEntryEntity);
 | 
						|
    
 | 
						|
    protected abstract void createChildEntryEntity(AVMChildEntryEntity childEntryEntity);
 | 
						|
    
 | 
						|
    protected abstract int updateChildEntryEntity(AVMChildEntryEntity childEntryEntity); // specific rename 'case' only
 | 
						|
    
 | 
						|
    protected abstract int deleteChildEntryEntity(long parentNodeId, String name);
 | 
						|
    protected abstract int deleteChildEntryEntity(long parentNodeId, long childNodeId);
 | 
						|
    protected abstract int deleteChildEntryEntities(long parentNodeId);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void createMergeLink(long mergeFromNodeId, long mergeToNodeId)
 | 
						|
    {
 | 
						|
        createMergeLinkEntity(mergeFromNodeId, mergeToNodeId);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void deleteMergeLink(long mergeFromNodeId, long mergeToNodeId)
 | 
						|
    {
 | 
						|
        AVMMergeLinkEntity mlEntity = getMergeLinkByTo(mergeToNodeId);
 | 
						|
        if (mlEntity == null)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        int deleted = deleteMergeLinkEntity(mergeFromNodeId, mergeToNodeId);
 | 
						|
        if (deleted < 1)
 | 
						|
        {
 | 
						|
            throw new ConcurrencyFailureException("AVMMergeLink (" + mergeFromNodeId + ", " + mergeToNodeId + ") no longer exists");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public AVMMergeLinkEntity getMergeLinkByTo(long mergeToNodeId)
 | 
						|
    {
 | 
						|
        return getMergeLinkEntityByTo(mergeToNodeId);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public List<AVMMergeLinkEntity> getMergeLinksByFrom(long mergeFromNodeId)
 | 
						|
    {
 | 
						|
        return getMergeLinkEntitiesByFrom(mergeFromNodeId);
 | 
						|
    }
 | 
						|
    
 | 
						|
    protected abstract void createMergeLinkEntity(long mergeFromNodeId, long mergeToNodeId);
 | 
						|
    protected abstract int deleteMergeLinkEntity(long mergeFromNodeId, long mergeToNodeId);
 | 
						|
    protected abstract AVMMergeLinkEntity getMergeLinkEntityByTo(long mergeToNodeId);
 | 
						|
    protected abstract List<AVMMergeLinkEntity> getMergeLinkEntitiesByFrom(long mergeFromNodeId);
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void createHistoryLink(long ancestorNodeId, long descendentNodeId)
 | 
						|
    {
 | 
						|
        AVMHistoryLinkEntity hlEntity = new AVMHistoryLinkEntity(ancestorNodeId, descendentNodeId);
 | 
						|
        
 | 
						|
        avmHistoryLinkCache.getOrCreateByValue(hlEntity); // ignore return value
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public void deleteHistoryLink(long ancestorNodeId, long descendentNodeId)
 | 
						|
    {
 | 
						|
        AVMHistoryLinkEntity hlEntity = new AVMHistoryLinkEntity(ancestorNodeId, descendentNodeId);
 | 
						|
        Pair<Long, AVMHistoryLinkEntity> entityPair = avmHistoryLinkCache.getByValue(hlEntity);
 | 
						|
        if (entityPair == null)
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        
 | 
						|
        int deleted = avmHistoryLinkCache.deleteByValue(hlEntity);
 | 
						|
        if (deleted < 1)
 | 
						|
        {
 | 
						|
            throw new ConcurrencyFailureException("AVMHistoryLinkEntity (" + ancestorNodeId + ", " + descendentNodeId + ") no longer exists");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public AVMHistoryLinkEntity getHistoryLinkByDescendent(long descendentNodeId)
 | 
						|
    {
 | 
						|
        Pair<Long, AVMHistoryLinkEntity> entityPair = avmHistoryLinkCache.getByKey(descendentNodeId);
 | 
						|
        if (entityPair == null)
 | 
						|
        {
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
        return entityPair.getSecond();
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * {@inheritDoc}
 | 
						|
     */
 | 
						|
    public List<AVMHistoryLinkEntity> getHistoryLinksByAncestor(long ancestorNodeId)
 | 
						|
    {
 | 
						|
        // not via cache
 | 
						|
        return getHistoryLinkEntitiesByAncestor(ancestorNodeId);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Callback for <b>avm_history_link</b> DAO
 | 
						|
     */
 | 
						|
    private class AVMHistoryLinkEntityCallbackDAO implements EntityLookupCallbackDAO<Long, AVMHistoryLinkEntity, AVMHistoryLinkEntity>
 | 
						|
    {
 | 
						|
        private final Pair<Long, AVMHistoryLinkEntity> convertEntityToPair(AVMHistoryLinkEntity hlEntity)
 | 
						|
        {
 | 
						|
            if (hlEntity == null)
 | 
						|
            {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                return new Pair<Long, AVMHistoryLinkEntity>(hlEntity.getDescendentNodeId(), hlEntity);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        public AVMHistoryLinkEntity getValueKey(AVMHistoryLinkEntity value)
 | 
						|
        {
 | 
						|
            return value;
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<Long, AVMHistoryLinkEntity> createValue(AVMHistoryLinkEntity value)
 | 
						|
        {
 | 
						|
            createHistoryLinkEntity(value.getAncestorNodeId(), value.getDescendentNodeId());
 | 
						|
            return convertEntityToPair(value);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<Long, AVMHistoryLinkEntity> findByKey(Long key)
 | 
						|
        {
 | 
						|
            AVMHistoryLinkEntity entity = getHistoryLinkEntityByDescendent(key);
 | 
						|
            return convertEntityToPair(entity);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public Pair<Long, AVMHistoryLinkEntity> findByValue(AVMHistoryLinkEntity value)
 | 
						|
        {
 | 
						|
            AVMHistoryLinkEntity entity = getHistoryLinkEntity(value.getAncestorNodeId(), value.getDescendentNodeId());
 | 
						|
            return convertEntityToPair(entity);
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int updateValue(Long key, AVMHistoryLinkEntity value)
 | 
						|
        {
 | 
						|
            throw new UnsupportedOperationException("updateValue(Long, AVMHistoryLinkEntity");
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int deleteByKey(Long key)
 | 
						|
        {
 | 
						|
            AVMHistoryLinkEntity entity = getHistoryLinkEntityByDescendent(key);
 | 
						|
            return deleteHistoryLinkEntity(entity.getAncestorNodeId(), entity.getDescendentNodeId());
 | 
						|
        }
 | 
						|
        
 | 
						|
        public int deleteByValue(AVMHistoryLinkEntity value)
 | 
						|
        {
 | 
						|
            return deleteHistoryLinkEntity(value.getAncestorNodeId(), value.getDescendentNodeId());
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    protected abstract void createHistoryLinkEntity(long ancestorNodeId, long descendentNodeId);
 | 
						|
    protected abstract int deleteHistoryLinkEntity(long ancestorNodeId, long descendentNodeId);
 | 
						|
    protected abstract AVMHistoryLinkEntity getHistoryLinkEntity(long ancestorNodeId, long descendentNodeId);
 | 
						|
    protected abstract AVMHistoryLinkEntity getHistoryLinkEntityByDescendent(long descendentNodeId);
 | 
						|
    protected abstract List<AVMHistoryLinkEntity> getHistoryLinkEntitiesByAncestor(long ancestorNodeId);
 | 
						|
}
 |