diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml index 29789aca16..316df932fe 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml @@ -26,13 +26,6 @@ - - - - - - - @@ -647,16 +640,12 @@ store.identifier = #{identifier} - + from alf_store store join alf_node node on (store.root_node_id = node.id) + join alf_transaction txn on (txn.id = node.transaction_id) where store.protocol = #{protocol} and store.identifier = #{identifier} diff --git a/source/java/org/alfresco/repo/cache/TransactionalCache.java b/source/java/org/alfresco/repo/cache/TransactionalCache.java index e5d4659269..4a81ecb664 100644 --- a/source/java/org/alfresco/repo/cache/TransactionalCache.java +++ b/source/java/org/alfresco/repo/cache/TransactionalCache.java @@ -954,7 +954,7 @@ public class TransactionalCache " Cache: " + sharedCache + "\n" + " Key: " + key + "\n" + " New Value: " + bucket.getValue() + "\n" + - " Cash Value: " + sharedCache.get(key), + " Cache Value:" + sharedCache.get(key), e); } } diff --git a/source/java/org/alfresco/repo/domain/node/NodeEntity.java b/source/java/org/alfresco/repo/domain/node/NodeEntity.java index 78ec20375a..e3c443d663 100644 --- a/source/java/org/alfresco/repo/domain/node/NodeEntity.java +++ b/source/java/org/alfresco/repo/domain/node/NodeEntity.java @@ -34,7 +34,7 @@ import org.alfresco.util.Pair; * @author Derek Hulley * @since 3.4 */ -public class NodeEntity implements Node, PermissionCheckValue, Serializable +public class NodeEntity implements Node, PermissionCheckValue, Serializable, Cloneable { private static final long serialVersionUID = 1L; private boolean locked; @@ -84,7 +84,13 @@ public class NodeEntity implements Node, PermissionCheckValue, Serializable this.transaction = node.getTransaction(); this.auditableProperties = node.getAuditableProperties(); } - + + @Override + public Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + @Override public int hashCode() { diff --git a/source/test-java/org/alfresco/repo/domain/node/NodeDAOTest.java b/source/test-java/org/alfresco/repo/domain/node/NodeDAOTest.java index 945750f35e..2fe35bf5bd 100644 --- a/source/test-java/org/alfresco/repo/domain/node/NodeDAOTest.java +++ b/source/test-java/org/alfresco/repo/domain/node/NodeDAOTest.java @@ -18,12 +18,15 @@ */ package org.alfresco.repo.domain.node; +import java.io.Serializable; +import java.util.Collection; import java.util.Collections; import java.util.List; import junit.framework.TestCase; import org.alfresco.model.ContentModel; +import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; @@ -34,6 +37,7 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.Pair; +import org.junit.Assert; import org.junit.experimental.categories.Category; import org.springframework.context.ApplicationContext; @@ -53,7 +57,9 @@ public class NodeDAOTest extends TestCase private TransactionService transactionService; private RetryingTransactionHelper txnHelper; private NodeDAO nodeDAO; + private SimpleCache rootNodesCache; + @SuppressWarnings("unchecked") @Override public void setUp() { @@ -65,6 +71,7 @@ public class NodeDAOTest extends TestCase txnHelper.setMaxRetryWaitMs(50); nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); + rootNodesCache = (SimpleCache) ctx.getBean("node.rootNodesSharedCache"); } public void testTransaction() throws Throwable @@ -141,4 +148,35 @@ public class NodeDAOTest extends TestCase assertEquals("Store pair did not match. ", storePair, checkStorePair); } } + + /** + * Ensure that the {@link NodeEntity} values cached as root nodes are valid instances. + *

+ * ACE-987: NPE in NodeEntity during post-commit write through to shared cache + */ + public void testRootNodeCacheEntries() throws Throwable + { + // Get the stores + List> storeRefPairs = nodeDAO.getStores(); + assertTrue("No stores in the system.", storeRefPairs.size() > 0); + // Drop all cache entries and reload them one by one + for (Pair storeRefPair : storeRefPairs) + { + StoreRef storeRef = storeRefPair.getSecond(); + nodeDAO.getRootNode(storeRef); + } + // The cache should be populated again + Collection keys = rootNodesCache.getKeys(); + assertTrue("Cache entries were not populated. ", keys.size() > 0); + // Check each root node + for (Serializable key : keys) + { + NodeEntity node = (NodeEntity) rootNodesCache.get(key); + // Create a good value + NodeEntity clonedNode = (NodeEntity) node.clone(); + // Run equals and hashcode + node.hashCode(); + Assert.assertEquals(node, clonedNode); // Does NPE check implicitly + } + } } \ No newline at end of file