diff --git a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java index 46dafacc2d..8df8f271a2 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java @@ -148,24 +148,12 @@ public class ChildAssocImpl implements ChildAssoc, Serializable return false; } ChildAssoc that = (ChildAssoc) obj; - if (EqualsHelper.nullSafeEquals(id, that.getId())) - { - return true; - } - else - { - return ( - EqualsHelper.nullSafeEquals(this.getChild().getId(), that.getChild().getId()) - && EqualsHelper.nullSafeEquals(this.getQname(), that.getQname()) - && EqualsHelper.nullSafeEquals(this.getParent().getId(), that.getParent().getId()) - && EqualsHelper.nullSafeEquals(this.getTypeQName(), that.getTypeQName()) - ); - } + return EqualsHelper.nullSafeEquals(id, that.getId()); } public int hashCode() { - return (qName == null ? 0 : qName.hashCode()); + return (id == null ? 0 : id.hashCode()); } /** diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java index fc9f9535ba..99d9b3fc75 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java @@ -251,8 +251,8 @@ public class HibernateNodeTest extends BaseSpringTest assoc1.setQname(QName.createQName(null, "number1")); assoc1.setChildNodeName("number1"); assoc1.setChildNodeNameCrc(1); - assoc1.buildAssociation(containerNode, contentNode); getSession().save(assoc1); + assoc1.buildAssociation(containerNode, contentNode); // make another association between the same two parent and child nodes ChildAssoc assoc2 = new ChildAssocImpl(); @@ -261,8 +261,8 @@ public class HibernateNodeTest extends BaseSpringTest assoc2.setQname(QName.createQName(null, "number2")); assoc2.setChildNodeName("number2"); assoc2.setChildNodeNameCrc(2); - assoc2.buildAssociation(containerNode, contentNode); getSession().save(assoc2); + assoc2.buildAssociation(containerNode, contentNode); assertFalse("Hashcode incorrent", assoc2.hashCode() == 0); assertNotSame("Assoc equals failure", assoc1, assoc2); diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 6a9f0993ca..907d1e65b5 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -80,6 +80,7 @@ import org.springframework.util.Assert; public class DbNodeServiceImpl extends AbstractNodeServiceImpl { private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class); + private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths"); private DictionaryService dictionaryService; private NodeDaoService nodeDaoService; @@ -1361,6 +1362,24 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } // done + if (loggerPaths.isDebugEnabled()) + { + StringBuilder sb = new StringBuilder(256); + if (primaryOnly) + { + sb.append("Primary paths"); + } + else + { + sb.append("Paths"); + } + sb.append(" for node ").append(nodeRef); + for (Path path : paths) + { + sb.append("\n").append(" ").append(path); + } + loggerPaths.debug(sb); + } return paths; } diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index b2872cdeaf..c46fecd530 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -20,7 +20,9 @@ import java.io.Serializable; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; @@ -55,6 +57,8 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.hibernate.ObjectDeletedException; import org.hibernate.Query; import org.hibernate.Session; @@ -82,6 +86,8 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements private static final String QUERY_GET_CONTENT_DATA_STRINGS = "node.GetContentDataStrings"; private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress"; + private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class); + /** a uuid identifying this unique instance */ private final String uuid; @@ -415,22 +421,47 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements * Manually ensures that all cascading of associations is taken care of */ public void deleteNode(Node node, boolean cascade) + { + Set deletedChildAssocIds = new HashSet(10); + deleteNodeInternal(node, cascade, deletedChildAssocIds); + } + + /** + * + * @param node + * @param cascade true to cascade delete + * @param deletedChildAssocIds previously deleted child associations + */ + private void deleteNodeInternal(Node node, boolean cascade, Set deletedChildAssocIds) { // delete all parent assocs + if (logger.isDebugEnabled()) + { + logger.debug("Deleting parent assocs of node " + node.getId()); + } + Collection parentAssocs = node.getParentAssocs(); parentAssocs = new ArrayList(parentAssocs); for (ChildAssoc assoc : parentAssocs) { - deleteChildAssoc(assoc, false); // we don't cascade upwards + deleteChildAssocInternal(assoc, false, deletedChildAssocIds); // we don't cascade upwards } // delete all child assocs + if (logger.isDebugEnabled()) + { + logger.debug("Deleting child assocs of node " + node.getId()); + } Collection childAssocs = getChildAssocs(node); childAssocs = new ArrayList(childAssocs); for (ChildAssoc assoc : childAssocs) { - deleteChildAssoc(assoc, cascade); // potentially cascade downwards + deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); // potentially cascade downwards } // delete all node associations to and from + if (logger.isDebugEnabled()) + { + logger.debug("Deleting source and target assocs of node " + node.getId()); + } List nodeAssocs = getNodeAssocsToAndFrom(node); for (NodeAssoc assoc : nodeAssocs) { @@ -501,9 +532,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements assoc.setChildNodeNameCrc(-1L); // random names compete only with each other assoc.setQname(qname); assoc.setIsPrimary(isPrimary); - assoc.buildAssociation(parentNode, childNode); // persist it, catching the duplicate child name getHibernateTemplate().save(assoc); + // maintain inverse sets + assoc.buildAssociation(parentNode, childNode); // done return assoc; } @@ -565,7 +597,6 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements { Integer count = (Integer) getHibernateTemplate().execute(callback); // refresh the entity directly - getHibernateTemplate().refresh(childAssoc); if (count.intValue() == 0) { if (logger.isDebugEnabled()) @@ -573,6 +604,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements logger.debug("ChildAssoc not updated: " + childAssoc.getId()); } } + else + { + getHibernateTemplate().refresh(childAssoc); + } } catch (DataIntegrityViolationException e) { @@ -690,21 +725,53 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements } /** - * Manually enforces cascade deletions down primary associations + * Public level entry-point. */ public void deleteChildAssoc(ChildAssoc assoc, boolean cascade) { + Set deletedChildAssocIds = new HashSet(10); + deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); + } + + /** + * Cascade deletion of child associations, recording the IDs of deleted assocs. + * + * @param assoc the association to delete + * @param cascade true to cascade to the child node of the association + * @param deletedChildAssocIds already-deleted associations + */ + private void deleteChildAssocInternal(ChildAssoc assoc, boolean cascade, Set deletedChildAssocIds) + { + Long childAssocId = assoc.getId(); + if (deletedChildAssocIds.contains(childAssocId)) + { + if (logger.isDebugEnabled()) + { + logger.debug("Ignoring parent-child association " + assoc.getId()); + } + return; + } + + if (logger.isDebugEnabled()) + { + logger.debug( + "Deleting parent-child association " + assoc.getId() + + (cascade ? " with" : " without") + " cascade:" + + assoc.getParent().getId() + " -> " + assoc.getChild().getId()); + } + Node childNode = assoc.getChild(); // maintain inverse association sets assoc.removeAssociation(); // remove instance getHibernateTemplate().delete(assoc); + deletedChildAssocIds.add(childAssocId); // ensure that we don't attempt to delete it twice if (cascade && assoc.getIsPrimary()) // the assoc is primary { // delete the child node - deleteNode(childNode, cascade); + deleteNodeInternal(childNode, cascade, deletedChildAssocIds); /* * The child node deletion will cascade delete all assocs to * and from it, but we have safely removed this one, so no diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest.java index a30e255203..23619c9ffa 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest.java @@ -41,7 +41,6 @@ import org.alfresco.repo.dictionary.M2Model; import org.alfresco.repo.node.BaseNodeServiceTest; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.search.QueryRegisterComponent; -import org.alfresco.repo.search.impl.lucene.analysis.NumericEncoder; import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; import org.alfresco.repo.search.results.ChildAssocRefResultSet; import org.alfresco.repo.search.results.DetachedResultSet;