mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
103438: Working towards a fix for ACE-3948: BM-0004: Factor out select on alf_content_url table during file creation - Complement the 'getOrCreate' EntityCache calls with 'createOrGet' - Cleanup of ContentDataDAOImpl code before further changes: tabs, @Override, unused code, etc git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@103622 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -19,12 +19,14 @@
|
|||||||
package org.alfresco.repo.cache.lookup;
|
package org.alfresco.repo.cache.lookup;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.sql.Savepoint;
|
||||||
|
|
||||||
import org.alfresco.repo.cache.SimpleCache;
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
|
import org.alfresco.repo.domain.control.ControlDAO;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
import org.springframework.extensions.surf.util.ParameterCheck;
|
|
||||||
import org.springframework.dao.ConcurrencyFailureException;
|
import org.springframework.dao.ConcurrencyFailureException;
|
||||||
|
import org.springframework.extensions.surf.util.ParameterCheck;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache for two-way lookups of database entities. These are characterized by having a unique
|
* A cache for two-way lookups of database entities. These are characterized by having a unique
|
||||||
@@ -412,6 +414,48 @@ public class EntityLookupCache<K extends Serializable, V extends Object, VK exte
|
|||||||
return entityPair;
|
return entityPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to create the entity and, failing that, look it up.<br/>
|
||||||
|
* This method takes the opposite approach to {@link #getOrCreateByValue(Object)}, which assumes the entity's
|
||||||
|
* existence: in this case the entity is assumed to NOT exist.
|
||||||
|
* The {@link EntityLookupCallbackDAO#createValue(Object)} and {@link EntityLookupCallbackDAO#findByValue(Object)}
|
||||||
|
* will be used if necessary.<br/>
|
||||||
|
* <p/>
|
||||||
|
* Use this method when the data involved is seldom reused.
|
||||||
|
*
|
||||||
|
* @param value The entity value (<tt>null</tt> is allowed)
|
||||||
|
* @param controlDAO an essential DAO required in order to ensure a transactionally-safe attempt at data creation
|
||||||
|
* @return Returns the key-value pair (new or existing and never <tt>null</tt>)
|
||||||
|
*/
|
||||||
|
public Pair<K, V> createOrGetByValue(V value, ControlDAO controlDAO)
|
||||||
|
{
|
||||||
|
if (controlDAO == null)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("The ControlDAO is required in order to perform a safe attempted insert.");
|
||||||
|
}
|
||||||
|
Savepoint savepoint = controlDAO.createSavepoint("EntityLookupCache.createOrGetByValue");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Pair<K, V> entityPair = entityLookup.createValue(value);
|
||||||
|
controlDAO.releaseSavepoint(savepoint);
|
||||||
|
// Cache it
|
||||||
|
if (cache != null)
|
||||||
|
{
|
||||||
|
cache.put(
|
||||||
|
new CacheRegionKey(cacheRegion, entityPair.getFirst()),
|
||||||
|
(entityPair.getSecond() == null ? VALUE_NULL : entityPair.getSecond()));
|
||||||
|
}
|
||||||
|
// It's been created and cached
|
||||||
|
return entityPair;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
controlDAO.rollbackToSavepoint(savepoint);
|
||||||
|
// Fall through to the usual way, which should find it if the failure cause was a duplicate key
|
||||||
|
return getOrCreateByValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the entity associated with the given value and create it if it doesn't exist.
|
* Find the entity associated with the given value and create it if it doesn't exist.
|
||||||
* The {@link EntityLookupCallbackDAO#findByValue(Object)} and {@link EntityLookupCallbackDAO#createValue(Object)}
|
* The {@link EntityLookupCallbackDAO#findByValue(Object)} and {@link EntityLookupCallbackDAO#createValue(Object)}
|
||||||
|
@@ -82,6 +82,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
this.template = sqlSessionTemplate;
|
this.template = sqlSessionTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Pair<Long, String> createContentUrlOrphaned(String contentUrl, Date orphanTime)
|
public Pair<Long, String> createContentUrlOrphaned(String contentUrl, Date orphanTime)
|
||||||
{
|
{
|
||||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||||
@@ -107,8 +108,6 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
if(contentUrlKeyEntity != null)
|
if(contentUrlKeyEntity != null)
|
||||||
{
|
{
|
||||||
template.insert(INSERT_SYMMETRIC_KEY, contentUrlKeyEntity);
|
template.insert(INSERT_SYMMETRIC_KEY, contentUrlKeyEntity);
|
||||||
|
|
||||||
// contentUrlEntity.setContentUrlKey(contentUrlKeyEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
@@ -139,6 +138,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
return contentUrlEntity;
|
return contentUrlEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void getContentUrlsOrphaned(
|
public void getContentUrlsOrphaned(
|
||||||
final ContentUrlHandler contentUrlHandler,
|
final ContentUrlHandler contentUrlHandler,
|
||||||
final Long maxOrphanTimeExclusive,
|
final Long maxOrphanTimeExclusive,
|
||||||
@@ -161,7 +161,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@Override
|
||||||
public void getContentUrlsKeepOrphaned(
|
public void getContentUrlsKeepOrphaned(
|
||||||
final ContentUrlHandler contentUrlHandler,
|
final ContentUrlHandler contentUrlHandler,
|
||||||
final int maxResults)
|
final int maxResults)
|
||||||
@@ -178,6 +178,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int updateContentUrlOrphanTime(Long id, Long orphanTime, Long oldOrphanTime)
|
public int updateContentUrlOrphanTime(Long id, Long orphanTime, Long oldOrphanTime)
|
||||||
{
|
{
|
||||||
ContentUrlUpdateEntity contentUrlUpdateEntity = new ContentUrlUpdateEntity();
|
ContentUrlUpdateEntity contentUrlUpdateEntity = new ContentUrlUpdateEntity();
|
||||||
@@ -190,6 +191,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int deleteContentUrls(List<Long> ids)
|
public int deleteContentUrls(List<Long> ids)
|
||||||
{
|
{
|
||||||
template.delete(DELETE_CONTENT_URL_KEYS, ids);
|
template.delete(DELETE_CONTENT_URL_KEYS, ids);
|
||||||
@@ -289,6 +291,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
|||||||
return template.delete(DELETE_CONTENT_DATA, params);
|
return template.delete(DELETE_CONTENT_DATA, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void deleteContentDataForNode(Long nodeId, Set<Long> qnameIds)
|
public void deleteContentDataForNode(Long nodeId, Set<Long> qnameIds)
|
||||||
{
|
{
|
||||||
if (qnameIds.size() == 0)
|
if (qnameIds.size() == 0)
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.cache.lookup;
|
package org.alfresco.repo.cache.lookup;
|
||||||
|
|
||||||
|
import java.sql.Savepoint;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@@ -27,8 +28,11 @@ import junit.framework.TestCase;
|
|||||||
import org.alfresco.repo.cache.MemoryCache;
|
import org.alfresco.repo.cache.MemoryCache;
|
||||||
import org.alfresco.repo.cache.SimpleCache;
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO;
|
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO;
|
||||||
|
import org.alfresco.repo.domain.control.ControlDAO;
|
||||||
import org.alfresco.util.EqualsHelper;
|
import org.alfresco.util.EqualsHelper;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache for two-way lookups of database entities. These are characterized by having a unique
|
* A cache for two-way lookups of database entities. These are characterized by having a unique
|
||||||
@@ -46,6 +50,7 @@ public class EntityLookupCacheTest extends TestCase implements EntityLookupCallb
|
|||||||
private EntityLookupCache<Long, Object, String> entityLookupCacheA;
|
private EntityLookupCache<Long, Object, String> entityLookupCacheA;
|
||||||
private EntityLookupCache<Long, Object, String> entityLookupCacheB;
|
private EntityLookupCache<Long, Object, String> entityLookupCacheB;
|
||||||
private TreeMap<Long, String> database;
|
private TreeMap<Long, String> database;
|
||||||
|
private ControlDAO controlDAO;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception
|
protected void setUp() throws Exception
|
||||||
@@ -54,6 +59,9 @@ public class EntityLookupCacheTest extends TestCase implements EntityLookupCallb
|
|||||||
entityLookupCacheA = new EntityLookupCache<Long, Object, String>(cache, "A", this);
|
entityLookupCacheA = new EntityLookupCache<Long, Object, String>(cache, "A", this);
|
||||||
entityLookupCacheB = new EntityLookupCache<Long, Object, String>(cache, "B", this);
|
entityLookupCacheB = new EntityLookupCache<Long, Object, String>(cache, "B", this);
|
||||||
database = new TreeMap<Long, String>();
|
database = new TreeMap<Long, String>();
|
||||||
|
|
||||||
|
controlDAO = Mockito.mock(ControlDAO.class);
|
||||||
|
Mockito.when(controlDAO.createSavepoint(Mockito.anyString())).thenReturn(Mockito.mock(Savepoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testLookupsUsingIncorrectValue() throws Exception
|
public void testLookupsUsingIncorrectValue() throws Exception
|
||||||
@@ -159,6 +167,34 @@ public class EntityLookupCacheTest extends TestCase implements EntityLookupCallb
|
|||||||
assertEquals(entityPairNull, entityPairCheck);
|
assertEquals(entityPairNull, entityPairCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetOrCreate() throws Exception
|
||||||
|
{
|
||||||
|
TestValue valueOne = new TestValue(getName() + "-ONE");
|
||||||
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
|
assertNotNull(entityPairOne);
|
||||||
|
Long id = entityPairOne.getFirst();
|
||||||
|
assertEquals(valueOne.val, database.get(id));
|
||||||
|
assertEquals(2, cache.getKeys().size());
|
||||||
|
|
||||||
|
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
|
assertNotNull(entityPairOneCheck);
|
||||||
|
assertEquals(id, entityPairOneCheck.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateOrGet() throws Exception
|
||||||
|
{
|
||||||
|
TestValue valueOne = new TestValue(getName() + "-ONE");
|
||||||
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
||||||
|
assertNotNull(entityPairOne);
|
||||||
|
Long id = entityPairOne.getFirst();
|
||||||
|
assertEquals(valueOne.val, database.get(id));
|
||||||
|
assertEquals(1, cache.getKeys().size());
|
||||||
|
|
||||||
|
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
||||||
|
assertNotNull(entityPairOneCheck);
|
||||||
|
assertEquals(id, entityPairOneCheck.getFirst());
|
||||||
|
}
|
||||||
|
|
||||||
public void testUpdate() throws Exception
|
public void testUpdate() throws Exception
|
||||||
{
|
{
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
TestValue valueOne = new TestValue(getName() + "-ONE");
|
||||||
@@ -295,6 +331,12 @@ public class EntityLookupCacheTest extends TestCase implements EntityLookupCallb
|
|||||||
assertTrue(value == null || value instanceof TestValue);
|
assertTrue(value == null || value instanceof TestValue);
|
||||||
String dbValue = (value == null) ? null : ((TestValue)value).val;
|
String dbValue = (value == null) ? null : ((TestValue)value).val;
|
||||||
|
|
||||||
|
// Kick out any duplicate values
|
||||||
|
if (database.containsValue(dbValue))
|
||||||
|
{
|
||||||
|
throw new DuplicateKeyException("Value is duplicated: " + value);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the last key
|
// Get the last key
|
||||||
Long lastKey = database.isEmpty() ? null : database.lastKey();
|
Long lastKey = database.isEmpty() ? null : database.lastKey();
|
||||||
Long newKey = null;
|
Long newKey = null;
|
||||||
|
Reference in New Issue
Block a user