mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
MNT-24641 Avoid duplicate key error on content upload (#2984)
MNT-24641 * On createOrGetByValue in EntityLookupCache, also cache by value * Created getCachedEntityByValue that attempt to retrieve the value only from cache * On attempt to create content URL, first check cache before attempting to create in the database avoiding a duplicate key
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,391 +21,431 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
package org.alfresco.repo.cache.lookup;
|
package org.alfresco.repo.cache.lookup;
|
||||||
|
|
||||||
import java.sql.Savepoint;
|
import static org.junit.Assert.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
import java.sql.Savepoint;
|
||||||
|
import java.util.Map;
|
||||||
import junit.framework.AssertionFailedError;
|
import java.util.TreeMap;
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
import org.alfresco.repo.cache.MemoryCache;
|
import org.junit.Before;
|
||||||
import org.alfresco.repo.cache.SimpleCache;
|
import org.junit.Test;
|
||||||
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO;
|
import org.mockito.Mockito;
|
||||||
import org.alfresco.repo.domain.control.ControlDAO;
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
import org.alfresco.util.EqualsHelper;
|
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.repo.cache.MemoryCache;
|
||||||
import org.mockito.Mockito;
|
import org.alfresco.repo.cache.SimpleCache;
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO;
|
||||||
|
import org.alfresco.repo.domain.control.ControlDAO;
|
||||||
/**
|
import org.alfresco.util.EqualsHelper;
|
||||||
* A cache for two-way lookups of database entities. These are characterized by having a unique
|
import org.alfresco.util.Pair;
|
||||||
* key (perhaps a database ID) and a separate unique key that identifies the object.
|
|
||||||
* <p>
|
/**
|
||||||
* The keys must have good <code>equals</code> and </code>hashCode</code> implementations and
|
* A cache for two-way lookups of database entities. These are characterized by having a unique key (perhaps a database ID) and a separate unique key that identifies the object.
|
||||||
* must respect the case-sensitivity of the use-case.
|
* <p>
|
||||||
*
|
* The keys must have good <code>equals</code> and </code>hashCode</code> implementations and must respect the case-sensitivity of the use-case.
|
||||||
* @author Derek Hulley
|
*
|
||||||
* @since 3.2
|
* @author Derek Hulley
|
||||||
*/
|
* @since 3.2
|
||||||
public class EntityLookupCacheTest extends TestCase implements EntityLookupCallbackDAO<Long, Object, String>
|
*/
|
||||||
{
|
public class EntityLookupCacheTest implements EntityLookupCallbackDAO<Long, Object, String>
|
||||||
SimpleCache<Long, Object> cache;
|
{
|
||||||
private EntityLookupCache<Long, Object, String> entityLookupCacheA;
|
SimpleCache<Long, Object> cache;
|
||||||
private EntityLookupCache<Long, Object, String> entityLookupCacheB;
|
private EntityLookupCache<Long, Object, String> entityLookupCacheA;
|
||||||
private TreeMap<Long, String> database;
|
private EntityLookupCache<Long, Object, String> entityLookupCacheB;
|
||||||
private ControlDAO controlDAO;
|
private TreeMap<Long, String> database;
|
||||||
|
private ControlDAO controlDAO;
|
||||||
@Override
|
|
||||||
protected void setUp() throws Exception
|
@Before
|
||||||
{
|
protected void setUp() throws Exception
|
||||||
cache = new MemoryCache<Long, Object>();
|
{
|
||||||
entityLookupCacheA = new EntityLookupCache<Long, Object, String>(cache, "A", this);
|
cache = new MemoryCache<Long, Object>();
|
||||||
entityLookupCacheB = new EntityLookupCache<Long, Object, String>(cache, "B", this);
|
entityLookupCacheA = new EntityLookupCache<Long, Object, String>(cache, "A", this);
|
||||||
database = new TreeMap<Long, String>();
|
entityLookupCacheB = new EntityLookupCache<Long, Object, String>(cache, "B", this);
|
||||||
|
database = new TreeMap<Long, String>();
|
||||||
controlDAO = Mockito.mock(ControlDAO.class);
|
|
||||||
Mockito.when(controlDAO.createSavepoint(Mockito.anyString())).thenReturn(Mockito.mock(Savepoint.class));
|
controlDAO = Mockito.mock(ControlDAO.class);
|
||||||
}
|
Mockito.when(controlDAO.createSavepoint(Mockito.anyString())).thenReturn(Mockito.mock(Savepoint.class));
|
||||||
|
}
|
||||||
public void testLookupsUsingIncorrectValue() throws Exception
|
|
||||||
{
|
@Test
|
||||||
try
|
public void testLookupsUsingIncorrectValue() throws Exception
|
||||||
{
|
{
|
||||||
// Keep the "database" empty
|
try
|
||||||
entityLookupCacheA.getByValue(this);
|
{
|
||||||
}
|
// Keep the "database" empty
|
||||||
catch (AssertionFailedError e)
|
entityLookupCacheA.getByValue(this);
|
||||||
{
|
}
|
||||||
// Expected
|
catch (AssertionFailedError e)
|
||||||
}
|
{
|
||||||
}
|
// Expected
|
||||||
|
}
|
||||||
public void testLookupAgainstEmpty() throws Exception
|
}
|
||||||
{
|
|
||||||
TestValue value = new TestValue("AAA");
|
@Test
|
||||||
Pair<Long, Object> entityPair = entityLookupCacheA.getByValue(value);
|
public void testLookupAgainstEmpty() throws Exception
|
||||||
assertNull(entityPair);
|
{
|
||||||
assertTrue(database.isEmpty());
|
TestValue value = new TestValue("AAA");
|
||||||
|
Pair<Long, Object> entityPair = entityLookupCacheA.getByValue(value);
|
||||||
// Now do lookup or create
|
assertNull(entityPair);
|
||||||
entityPair = entityLookupCacheA.getOrCreateByValue(value);
|
assertTrue(database.isEmpty());
|
||||||
assertNotNull("Expected a value to be found", entityPair);
|
|
||||||
Long entityId = entityPair.getFirst();
|
// Now do lookup or create
|
||||||
assertTrue("Database ID should have been created", database.containsKey(entityId));
|
entityPair = entityLookupCacheA.getOrCreateByValue(value);
|
||||||
assertEquals("Database value incorrect", value.val, database.get(entityId));
|
assertNotNull("Expected a value to be found", entityPair);
|
||||||
|
Long entityId = entityPair.getFirst();
|
||||||
// Do lookup or create again
|
assertTrue("Database ID should have been created", database.containsKey(entityId));
|
||||||
entityPair = entityLookupCacheA.getOrCreateByValue(value);
|
assertEquals("Database value incorrect", value.val, database.get(entityId));
|
||||||
assertNotNull("Expected a value to be found", entityPair);
|
|
||||||
assertEquals("Expected same entity ID", entityId, entityPair.getFirst());
|
// Do lookup or create again
|
||||||
|
entityPair = entityLookupCacheA.getOrCreateByValue(value);
|
||||||
// Look it up using the value
|
assertNotNull("Expected a value to be found", entityPair);
|
||||||
entityPair = entityLookupCacheA.getByValue(value);
|
assertEquals("Expected same entity ID", entityId, entityPair.getFirst());
|
||||||
assertNotNull("Lookup after create should work", entityPair);
|
|
||||||
|
// Look it up using the value
|
||||||
// Look it up using the ID
|
entityPair = entityLookupCacheA.getByValue(value);
|
||||||
entityPair = entityLookupCacheA.getByKey(entityId);
|
assertNotNull("Lookup after create should work", entityPair);
|
||||||
assertNotNull("Lookup by key should work after create", entityPair);
|
|
||||||
assertTrue("Looked-up type incorrect", entityPair.getSecond() instanceof TestValue);
|
// Look it up using the ID
|
||||||
assertEquals("Looked-up type value incorrect", value, entityPair.getSecond());
|
entityPair = entityLookupCacheA.getByKey(entityId);
|
||||||
}
|
assertNotNull("Lookup by key should work after create", entityPair);
|
||||||
|
assertTrue("Looked-up type incorrect", entityPair.getSecond() instanceof TestValue);
|
||||||
public void testLookupAgainstExisting() throws Exception
|
assertEquals("Looked-up type value incorrect", value, entityPair.getSecond());
|
||||||
{
|
}
|
||||||
// Put some values in the "database"
|
|
||||||
createValue(new TestValue("AAA"));
|
@Test
|
||||||
createValue(new TestValue("BBB"));
|
public void testLookupAgainstExisting() throws Exception
|
||||||
createValue(new TestValue("CCC"));
|
{
|
||||||
|
// Put some values in the "database"
|
||||||
// Look up by value
|
createValue(new TestValue("AAA"));
|
||||||
Pair<Long, Object> entityPair = entityLookupCacheA.getByValue(new TestValue("AAA"));
|
createValue(new TestValue("BBB"));
|
||||||
assertNotNull("Expected value to be found", entityPair);
|
createValue(new TestValue("CCC"));
|
||||||
assertEquals("ID is incorrect", Long.valueOf(1), entityPair.getFirst());
|
|
||||||
|
// Look up by value
|
||||||
// Look up by ID
|
Pair<Long, Object> entityPair = entityLookupCacheA.getByValue(new TestValue("AAA"));
|
||||||
entityPair = entityLookupCacheA.getByKey(Long.valueOf(2));
|
assertNotNull("Expected value to be found", entityPair);
|
||||||
assertNotNull("Expected value to be found", entityPair);
|
assertEquals("ID is incorrect", Long.valueOf(1), entityPair.getFirst());
|
||||||
|
|
||||||
// Do lookup or create
|
// Look up by ID
|
||||||
entityPair = entityLookupCacheA.getByValue(new TestValue("CCC"));
|
entityPair = entityLookupCacheA.getByKey(Long.valueOf(2));
|
||||||
assertNotNull("Expected value to be found", entityPair);
|
assertNotNull("Expected value to be found", entityPair);
|
||||||
assertEquals("ID is incorrect", Long.valueOf(3), entityPair.getFirst());
|
|
||||||
}
|
// Do lookup or create
|
||||||
|
entityPair = entityLookupCacheA.getByValue(new TestValue("CCC"));
|
||||||
public void testRegions() throws Exception
|
assertNotNull("Expected value to be found", entityPair);
|
||||||
{
|
assertEquals("ID is incorrect", Long.valueOf(3), entityPair.getFirst());
|
||||||
TestValue valueAAA = new TestValue("AAA");
|
}
|
||||||
Pair<Long, Object> entityPairAAA = entityLookupCacheA.getOrCreateByValue(valueAAA);
|
|
||||||
assertNotNull(entityPairAAA);
|
@Test
|
||||||
assertEquals("AAA", database.get(entityPairAAA.getFirst()));
|
public void testRegions() throws Exception
|
||||||
assertEquals(2, cache.getKeys().size());
|
{
|
||||||
|
TestValue valueAAA = new TestValue("AAA");
|
||||||
TestValue valueBBB = new TestValue("BBB");
|
Pair<Long, Object> entityPairAAA = entityLookupCacheA.getOrCreateByValue(valueAAA);
|
||||||
Pair<Long, Object> entityPairBBB = entityLookupCacheB.getOrCreateByValue(valueBBB);
|
assertNotNull(entityPairAAA);
|
||||||
assertNotNull(entityPairBBB);
|
assertEquals("AAA", database.get(entityPairAAA.getFirst()));
|
||||||
assertEquals("BBB", database.get(entityPairBBB.getFirst()));
|
assertEquals(2, cache.getKeys().size());
|
||||||
assertEquals(4, cache.getKeys().size());
|
|
||||||
|
TestValue valueBBB = new TestValue("BBB");
|
||||||
// Now cross-check against the caches and make sure that the cache
|
Pair<Long, Object> entityPairBBB = entityLookupCacheB.getOrCreateByValue(valueBBB);
|
||||||
entityPairBBB = entityLookupCacheA.getByValue(valueBBB);
|
assertNotNull(entityPairBBB);
|
||||||
assertEquals(6, cache.getKeys().size());
|
assertEquals("BBB", database.get(entityPairBBB.getFirst()));
|
||||||
entityPairBBB = entityLookupCacheB.getByValue(valueAAA);
|
assertEquals(4, cache.getKeys().size());
|
||||||
assertEquals(8, cache.getKeys().size());
|
|
||||||
}
|
// Now cross-check against the caches and make sure that the cache
|
||||||
|
entityPairBBB = entityLookupCacheA.getByValue(valueBBB);
|
||||||
public void testNullLookups() throws Exception
|
assertEquals(6, cache.getKeys().size());
|
||||||
{
|
entityPairBBB = entityLookupCacheB.getByValue(valueAAA);
|
||||||
TestValue valueNull = null;
|
assertEquals(8, cache.getKeys().size());
|
||||||
Pair<Long, Object> entityPairNull = entityLookupCacheA.getOrCreateByValue(valueNull);
|
}
|
||||||
assertNotNull(entityPairNull);
|
|
||||||
assertTrue(database.containsKey(entityPairNull.getFirst()));
|
@Test
|
||||||
assertNull(database.get(entityPairNull.getFirst()));
|
public void testNullLookups() throws Exception
|
||||||
assertEquals(2, cache.getKeys().size());
|
{
|
||||||
|
TestValue valueNull = null;
|
||||||
// Look it up again
|
Pair<Long, Object> entityPairNull = entityLookupCacheA.getOrCreateByValue(valueNull);
|
||||||
Pair<Long, Object> entityPairCheck = entityLookupCacheA.getOrCreateByValue(valueNull);
|
assertNotNull(entityPairNull);
|
||||||
assertNotNull(entityPairNull);
|
assertTrue(database.containsKey(entityPairNull.getFirst()));
|
||||||
assertTrue(database.containsKey(entityPairNull.getFirst()));
|
assertNull(database.get(entityPairNull.getFirst()));
|
||||||
assertNull(database.get(entityPairNull.getFirst()));
|
assertEquals(2, cache.getKeys().size());
|
||||||
assertEquals(entityPairNull, entityPairCheck);
|
|
||||||
}
|
// Look it up again
|
||||||
|
Pair<Long, Object> entityPairCheck = entityLookupCacheA.getOrCreateByValue(valueNull);
|
||||||
public void testGetOrCreate() throws Exception
|
assertNotNull(entityPairNull);
|
||||||
{
|
assertTrue(database.containsKey(entityPairNull.getFirst()));
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
assertNull(database.get(entityPairNull.getFirst()));
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
assertEquals(entityPairNull, entityPairCheck);
|
||||||
assertNotNull(entityPairOne);
|
}
|
||||||
Long id = entityPairOne.getFirst();
|
|
||||||
assertEquals(valueOne.val, database.get(id));
|
@Test
|
||||||
assertEquals(2, cache.getKeys().size());
|
public void testGetOrCreate() throws Exception
|
||||||
|
{
|
||||||
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.getOrCreateByValue(valueOne);
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
assertNotNull(entityPairOneCheck);
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
assertEquals(id, entityPairOneCheck.getFirst());
|
assertNotNull(entityPairOne);
|
||||||
}
|
Long id = entityPairOne.getFirst();
|
||||||
|
assertEquals(valueOne.val, database.get(id));
|
||||||
public void testCreateOrGet() throws Exception
|
assertEquals(2, cache.getKeys().size());
|
||||||
{
|
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
assertNotNull(entityPairOneCheck);
|
||||||
assertNotNull(entityPairOne);
|
assertEquals(id, entityPairOneCheck.getFirst());
|
||||||
Long id = entityPairOne.getFirst();
|
}
|
||||||
assertEquals(valueOne.val, database.get(id));
|
|
||||||
assertEquals(1, cache.getKeys().size());
|
@Test
|
||||||
|
public void testCreateOrGet() throws Exception
|
||||||
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
{
|
||||||
assertNotNull(entityPairOneCheck);
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
assertEquals(id, entityPairOneCheck.getFirst());
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
||||||
}
|
assertNotNull(entityPairOne);
|
||||||
|
Long id = entityPairOne.getFirst();
|
||||||
public void testUpdate() throws Exception
|
assertEquals(valueOne.val, database.get(id));
|
||||||
{
|
// We cache both by value and by key, so we should have 2 entries
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
assertEquals(2, cache.getKeys().size());
|
||||||
TestValue valueTwo = new TestValue(getName() + "-TWO");
|
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
Pair<Long, Object> entityPairOneCheck = entityLookupCacheA.createOrGetByValue(valueOne, controlDAO);
|
||||||
assertNotNull(entityPairOne);
|
assertNotNull(entityPairOneCheck);
|
||||||
Long id = entityPairOne.getFirst();
|
assertEquals(id, entityPairOneCheck.getFirst());
|
||||||
assertEquals(valueOne.val, database.get(id));
|
}
|
||||||
assertEquals(2, cache.getKeys().size());
|
|
||||||
|
@Test
|
||||||
// Update
|
public void testUpdate() throws Exception
|
||||||
int updateCount = entityLookupCacheA.updateValue(id, valueTwo);
|
{
|
||||||
assertEquals("Update count was incorrect.", 1, updateCount);
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
assertEquals(valueTwo.val, database.get(id));
|
TestValue valueTwo = new TestValue(getClass().getName() + "-TWO");
|
||||||
assertEquals(2, cache.getKeys().size());
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
}
|
assertNotNull(entityPairOne);
|
||||||
|
Long id = entityPairOne.getFirst();
|
||||||
public void testDeleteByKey() throws Exception
|
assertEquals(valueOne.val, database.get(id));
|
||||||
{
|
assertEquals(2, cache.getKeys().size());
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
// Update
|
||||||
assertNotNull(entityPairOne);
|
int updateCount = entityLookupCacheA.updateValue(id, valueTwo);
|
||||||
Long id = entityPairOne.getFirst();
|
assertEquals("Update count was incorrect.", 1, updateCount);
|
||||||
assertEquals(valueOne.val, database.get(id));
|
assertEquals(valueTwo.val, database.get(id));
|
||||||
assertEquals(2, cache.getKeys().size());
|
assertEquals(2, cache.getKeys().size());
|
||||||
|
}
|
||||||
// Delete
|
|
||||||
int deleteCount = entityLookupCacheA.deleteByKey(id);
|
@Test
|
||||||
assertEquals("Delete count was incorrect.", 1, deleteCount);
|
public void testDeleteByKey() throws Exception
|
||||||
assertNull(database.get(id));
|
{
|
||||||
assertEquals(0, cache.getKeys().size());
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
}
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
|
assertNotNull(entityPairOne);
|
||||||
public void testDeleteByValue() throws Exception
|
Long id = entityPairOne.getFirst();
|
||||||
{
|
assertEquals(valueOne.val, database.get(id));
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
assertEquals(2, cache.getKeys().size());
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
|
||||||
assertNotNull(entityPairOne);
|
// Delete
|
||||||
Long id = entityPairOne.getFirst();
|
int deleteCount = entityLookupCacheA.deleteByKey(id);
|
||||||
assertEquals(valueOne.val, database.get(id));
|
assertEquals("Delete count was incorrect.", 1, deleteCount);
|
||||||
assertEquals(2, cache.getKeys().size());
|
assertNull(database.get(id));
|
||||||
|
assertEquals(0, cache.getKeys().size());
|
||||||
// Delete
|
}
|
||||||
int deleteCount = entityLookupCacheA.deleteByValue(valueOne);
|
|
||||||
assertEquals("Delete count was incorrect.", 1, deleteCount);
|
@Test
|
||||||
assertNull(database.get(id));
|
public void testDeleteByValue() throws Exception
|
||||||
assertEquals(0, cache.getKeys().size());
|
{
|
||||||
}
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
public void testClear() throws Exception
|
assertNotNull(entityPairOne);
|
||||||
{
|
Long id = entityPairOne.getFirst();
|
||||||
TestValue valueOne = new TestValue(getName() + "-ONE");
|
assertEquals(valueOne.val, database.get(id));
|
||||||
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
assertEquals(2, cache.getKeys().size());
|
||||||
assertNotNull(entityPairOne);
|
|
||||||
Long id = entityPairOne.getFirst();
|
// Delete
|
||||||
assertEquals(valueOne.val, database.get(id));
|
int deleteCount = entityLookupCacheA.deleteByValue(valueOne);
|
||||||
assertEquals(2, cache.getKeys().size());
|
assertEquals("Delete count was incorrect.", 1, deleteCount);
|
||||||
|
assertNull(database.get(id));
|
||||||
// Clear it
|
assertEquals(0, cache.getKeys().size());
|
||||||
entityLookupCacheA.clear();
|
}
|
||||||
assertEquals(valueOne.val, database.get(id)); // Must still be in database
|
|
||||||
assertEquals(0, cache.getKeys().size()); // ... but cache must be empty
|
@Test
|
||||||
}
|
public void testClear() throws Exception
|
||||||
|
{
|
||||||
/**
|
TestValue valueOne = new TestValue(getClass().getName() + "-ONE");
|
||||||
* Helper class to represent business object
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.getOrCreateByValue(valueOne);
|
||||||
*/
|
assertNotNull(entityPairOne);
|
||||||
private static class TestValue
|
Long id = entityPairOne.getFirst();
|
||||||
{
|
assertEquals(valueOne.val, database.get(id));
|
||||||
private final String val;
|
assertEquals(2, cache.getKeys().size());
|
||||||
private TestValue(String val)
|
|
||||||
{
|
// Clear it
|
||||||
this.val = val;
|
entityLookupCacheA.clear();
|
||||||
}
|
assertEquals(valueOne.val, database.get(id)); // Must still be in database
|
||||||
@Override
|
assertEquals(0, cache.getKeys().size()); // ... but cache must be empty
|
||||||
public boolean equals(Object obj)
|
}
|
||||||
{
|
|
||||||
if (obj == null || !(obj instanceof TestValue))
|
@Test
|
||||||
{
|
public void testGetCachedValue() throws Exception
|
||||||
return false;
|
{
|
||||||
}
|
// Create a new value
|
||||||
return val.equals( ((TestValue)obj).val );
|
TestValue valueCached = new TestValue(getClass().getName() + "-CACHED");
|
||||||
}
|
Pair<Long, Object> entityPairOne = entityLookupCacheA.createOrGetByValue(valueCached, controlDAO);
|
||||||
@Override
|
assertNotNull(entityPairOne);
|
||||||
public int hashCode()
|
Long id = entityPairOne.getFirst();
|
||||||
{
|
// We cache both by value and by key, so we should have 2 entries
|
||||||
return val.hashCode();
|
assertEquals(2, cache.getKeys().size());
|
||||||
}
|
|
||||||
|
// Check the cache for the previously created value
|
||||||
}
|
Pair<Long, Object> entityPairCacheCheck = entityLookupCacheA.getCachedEntityByValue(valueCached);
|
||||||
|
assertNotNull(entityPairCacheCheck);
|
||||||
public String getValueKey(Object value)
|
assertEquals(id, entityPairCacheCheck.getFirst());
|
||||||
{
|
|
||||||
assertNotNull(value);
|
// Clear the cache and attempt to retrieve it again
|
||||||
assertTrue(value instanceof TestValue);
|
entityLookupCacheA.clear();
|
||||||
String dbValue = ((TestValue)value).val;
|
entityPairCacheCheck = entityLookupCacheA.getCachedEntityByValue(valueCached);
|
||||||
return dbValue;
|
|
||||||
}
|
// Since we are only retrieving from cache, the value should not be found
|
||||||
|
assertNull(entityPairCacheCheck);
|
||||||
public Pair<Long, Object> findByKey(Long key)
|
}
|
||||||
{
|
|
||||||
assertNotNull(key);
|
/**
|
||||||
|
* Helper class to represent business object
|
||||||
String dbValue = database.get(key);
|
*/
|
||||||
if (dbValue == null)
|
private static class TestValue
|
||||||
{
|
{
|
||||||
return null;
|
private final String val;
|
||||||
}
|
|
||||||
// Make a value object
|
private TestValue(String val)
|
||||||
TestValue value = new TestValue(dbValue);
|
{
|
||||||
return new Pair<Long, Object>(key, value);
|
this.val = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, Object> findByValue(Object value)
|
@Override
|
||||||
{
|
public boolean equals(Object obj)
|
||||||
assertTrue(value == null || value instanceof TestValue);
|
{
|
||||||
String dbValue = (value == null) ? null : ((TestValue)value).val;
|
if (obj == null || !(obj instanceof TestValue))
|
||||||
|
{
|
||||||
for (Map.Entry<Long, String> entry : database.entrySet())
|
return false;
|
||||||
{
|
}
|
||||||
if (EqualsHelper.nullSafeEquals(entry.getValue(), dbValue))
|
return val.equals(((TestValue) obj).val);
|
||||||
{
|
}
|
||||||
return new Pair<Long, Object>(entry.getKey(), entry.getValue());
|
|
||||||
}
|
@Override
|
||||||
}
|
public int hashCode()
|
||||||
return null;
|
{
|
||||||
}
|
return val.hashCode();
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Simulate creation of a new database entry
|
}
|
||||||
*/
|
|
||||||
public Pair<Long, Object> createValue(Object value)
|
public String getValueKey(Object value)
|
||||||
{
|
{
|
||||||
assertTrue(value == null || value instanceof TestValue);
|
assertNotNull(value);
|
||||||
String dbValue = (value == null) ? null : ((TestValue)value).val;
|
assertTrue(value instanceof TestValue);
|
||||||
|
String dbValue = ((TestValue) value).val;
|
||||||
// Kick out any duplicate values
|
return dbValue;
|
||||||
if (database.containsValue(dbValue))
|
}
|
||||||
{
|
|
||||||
throw new DuplicateKeyException("Value is duplicated: " + value);
|
public Pair<Long, Object> findByKey(Long key)
|
||||||
}
|
{
|
||||||
|
assertNotNull(key);
|
||||||
// Get the last key
|
|
||||||
Long lastKey = database.isEmpty() ? null : database.lastKey();
|
String dbValue = database.get(key);
|
||||||
Long newKey = null;
|
if (dbValue == null)
|
||||||
if (lastKey == null)
|
{
|
||||||
{
|
return null;
|
||||||
newKey = Long.valueOf(1);
|
}
|
||||||
}
|
// Make a value object
|
||||||
else
|
TestValue value = new TestValue(dbValue);
|
||||||
{
|
return new Pair<Long, Object>(key, value);
|
||||||
newKey = Long.valueOf(lastKey.longValue() + 1);
|
}
|
||||||
}
|
|
||||||
database.put(newKey, dbValue);
|
public Pair<Long, Object> findByValue(Object value)
|
||||||
return new Pair<Long, Object>(newKey, value);
|
{
|
||||||
}
|
assertTrue(value == null || value instanceof TestValue);
|
||||||
|
String dbValue = (value == null) ? null : ((TestValue) value).val;
|
||||||
public int updateValue(Long key, Object value)
|
|
||||||
{
|
for (Map.Entry<Long, String> entry : database.entrySet())
|
||||||
assertNotNull(key);
|
{
|
||||||
assertTrue(value == null || value instanceof TestValue);
|
if (EqualsHelper.nullSafeEquals(entry.getValue(), dbValue))
|
||||||
|
{
|
||||||
// Find it
|
return new Pair<Long, Object>(entry.getKey(), entry.getValue());
|
||||||
Pair<Long, Object> entityPair = findByKey(key);
|
}
|
||||||
if (entityPair == null)
|
}
|
||||||
{
|
return null;
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
else
|
/**
|
||||||
{
|
* Simulate creation of a new database entry
|
||||||
database.put(key, ((TestValue)value).val);
|
*/
|
||||||
return 1;
|
public Pair<Long, Object> createValue(Object value)
|
||||||
}
|
{
|
||||||
}
|
assertTrue(value == null || value instanceof TestValue);
|
||||||
|
String dbValue = (value == null) ? null : ((TestValue) value).val;
|
||||||
public int deleteByKey(Long key)
|
|
||||||
{
|
// Kick out any duplicate values
|
||||||
assertNotNull(key);
|
if (database.containsValue(dbValue))
|
||||||
|
{
|
||||||
if (database.containsKey(key))
|
throw new DuplicateKeyException("Value is duplicated: " + value);
|
||||||
{
|
}
|
||||||
database.remove(key);
|
|
||||||
return 1;
|
// Get the last key
|
||||||
}
|
Long lastKey = database.isEmpty() ? null : database.lastKey();
|
||||||
else
|
Long newKey = null;
|
||||||
{
|
if (lastKey == null)
|
||||||
return 0;
|
{
|
||||||
}
|
newKey = Long.valueOf(1);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public int deleteByValue(Object value)
|
{
|
||||||
{
|
newKey = Long.valueOf(lastKey.longValue() + 1);
|
||||||
assertTrue(value == null || value instanceof TestValue);
|
}
|
||||||
|
database.put(newKey, dbValue);
|
||||||
// Find it
|
return new Pair<Long, Object>(newKey, value);
|
||||||
Pair<Long, Object> entityPair = findByValue(value);
|
}
|
||||||
if (entityPair == null)
|
|
||||||
{
|
public int updateValue(Long key, Object value)
|
||||||
return 0;
|
{
|
||||||
}
|
assertNotNull(key);
|
||||||
else
|
assertTrue(value == null || value instanceof TestValue);
|
||||||
{
|
|
||||||
database.remove(entityPair.getFirst());
|
// Find it
|
||||||
return 1;
|
Pair<Long, Object> entityPair = findByKey(key);
|
||||||
}
|
if (entityPair == null)
|
||||||
}
|
{
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
database.put(key, ((TestValue) value).val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteByKey(Long key)
|
||||||
|
{
|
||||||
|
assertNotNull(key);
|
||||||
|
|
||||||
|
if (database.containsKey(key))
|
||||||
|
{
|
||||||
|
database.remove(key);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteByValue(Object value)
|
||||||
|
{
|
||||||
|
assertTrue(value == null || value instanceof TestValue);
|
||||||
|
|
||||||
|
// Find it
|
||||||
|
Pair<Long, Object> entityPair = findByValue(value);
|
||||||
|
if (entityPair == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
database.remove(entityPair.getFirst());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user