diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-auditable-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-auditable-common-SqlMap.xml index 6adaf92bac..001930c8ad 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-auditable-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/query-auditable-common-SqlMap.xml @@ -18,8 +18,12 @@ - - + + + + + + @@ -60,19 +64,21 @@ childNode.audit_modified as audit_modified, childNode.audit_modifier as audit_modifier, prop_name.string_value as name, - targetAssoc.parent_node_id as target_node_id, + targetAssoc.target_node_id as target_node_id, targetAssoc.type_qname_id as target_assoc_type_id from alf_child_assoc assoc join alf_node childNode on (childNode.id = assoc.child_node_id) join alf_store childStore on (childStore.id = childNode.store_id) left join alf_node_properties prop_name on (prop_name.node_id = childNode.id and prop_name.qname_id = #{nameQNameId}) - left join alf_child_assoc targetAssoc on (childNode.id = targetAssoc.child_node_id) + left join alf_node_assoc targetAssoc on ( + childNode.id = targetAssoc.source_node_id + + and targetAssoc.type_qname_id = #{assocTypeId} + + ) where assoc.parent_node_id = #{parentNodeId} and childNode.type_qname_id = #{contentTypeQNameId} - - and targetAssoc.type_qname_id = #{assocTypeId} - diff --git a/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java b/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java index 1d7b3abf1c..66190fd919 100644 --- a/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java +++ b/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java @@ -40,6 +40,7 @@ import org.alfresco.repo.node.getchildren.GetChildrenWithTargetAssocsAuditableCa import org.alfresco.repo.node.getchildren.GetChildrenWithTargetAssocsAuditableCannedQueryFactory; import org.alfresco.repo.query.NodeBackedEntity; import org.alfresco.repo.query.NodeWithTargetsEntity; +import org.alfresco.repo.query.NodeWithTargetsEntity.TargetAndTypeId; import org.alfresco.repo.site.SiteServiceImpl; import org.alfresco.service.cmr.discussion.DiscussionService; import org.alfresco.service.cmr.discussion.PostInfo; @@ -608,11 +609,77 @@ public class DiscussionServiceImpl implements DiscussionService CannedQueryResults results = cq.execute(); // Prepare to invert - // TODO - Map idToNode = new HashMap(); - - // All done - return null; + Map idToNodeRef = new HashMap(); + for(NodeWithTargetsEntity e : results.getPage()) + { + idToNodeRef.put(e.getId(), e.getNodeRef()); + } + + Map> idToReplies = new HashMap>(); + for(NodeWithTargetsEntity e : results.getPage()) + { + for(TargetAndTypeId idP : e.getTargetIds()) + { + Long id = idP.getTargetId(); + NodeRef nodeRef = idToNodeRef.get(id); + if(nodeRef == null) + { + // References a node outside of this topic + continue; + } + if(id.equals(e.getId())) + { + // Self reference + continue; + } + if(! idToReplies.containsKey(nodeRef)) + { + idToReplies.put(nodeRef, new ArrayList()); + } + idToReplies.get(nodeRef).add(e); + } + } + + // Grab the list of NodeRefs to pre-load, and pre-load them + List preLoad = new ArrayList(); + calculateRepliesPreLoad(primaryPost.getNodeRef(), preLoad, idToReplies, levels); + nodeDAO.cacheNodes(preLoad); + + // Wrap + return wrap(primaryPost, idToReplies, levels); + } + private void calculateRepliesPreLoad(NodeRef nodeRef, List preLoad, + Map> idToReplies, int levels) + { + preLoad.add(nodeRef); + if(levels > 0) + { + List replies = idToReplies.get(nodeRef); + if(replies != null && replies.size() > 0) + { + for(NodeWithTargetsEntity entity : replies) + { + calculateRepliesPreLoad(entity.getNodeRef(), preLoad, idToReplies, levels-1); + } + } + } + } + private PostWithReplies wrap(PostInfo post, Map> idToReplies, int levels) + { + List replies = new ArrayList(); + if(levels > 0) + { + List replyEntities = idToReplies.get(post.getNodeRef()); + if(replyEntities != null && replyEntities.size() > 0) + { + for(NodeWithTargetsEntity entity : replyEntities) + { + PostInfo replyPost = buildPost(entity.getNodeRef(), post.getTopic(), entity.getName(), null); + replies.add(wrap(replyPost, idToReplies, levels-1)); + } + } + } + return new PostWithReplies(post, replies); } diff --git a/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java b/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java index 65b549a9a5..7499f26d8e 100644 --- a/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java +++ b/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java @@ -39,6 +39,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.discussion.DiscussionService; import org.alfresco.service.cmr.discussion.PostInfo; +import org.alfresco.service.cmr.discussion.PostWithReplies; import org.alfresco.service.cmr.discussion.TopicInfo; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -686,7 +687,56 @@ public class DiscussionServiceImplTest for(TopicInfo topic : new TopicInfo[] {siteT1, nodeT1}) { // Listing initially gives nothing + PostWithReplies pr = DISCUSSION_SERVICE.listPostReplies(topic, 1); + assertEquals(null, pr); + // Add the first post + PostInfo post = DISCUSSION_SERVICE.createPost(topic, "Post"); + + // Should come back with no replies + pr = DISCUSSION_SERVICE.listPostReplies(topic, 1); + assertNotNull(pr); + assertEquals(post.getNodeRef(), pr.getNodeRef()); + assertEquals(0, pr.getReplies().size()); + + + // Add two replies + PostInfo reply1 = DISCUSSION_SERVICE.createReply(post, "R1"); + PostInfo reply2 = DISCUSSION_SERVICE.createReply(post, "R2"); + + + // Ask for the replies to the post + pr = DISCUSSION_SERVICE.listPostReplies(topic, 1); + assertNotNull(pr); + assertEquals(post.getNodeRef(), pr.getNodeRef()); + assertEquals(2, pr.getReplies().size()); + + assertEquals(reply1.getNodeRef(), pr.getReplies().get(0).getNodeRef()); + assertEquals(reply2.getNodeRef(), pr.getReplies().get(1).getNodeRef()); + assertEquals(0, pr.getReplies().get(0).getReplies().size()); + assertEquals(0, pr.getReplies().get(1).getReplies().size()); + + + // Check at other levels too: + // Level 0 will mean no replies were fetched + pr = DISCUSSION_SERVICE.listPostReplies(topic, 0); + assertNotNull(pr); + assertEquals(post.getNodeRef(), pr.getNodeRef()); + assertEquals(0, pr.getReplies().size()); + + // Level 5 won't affect things, as there are only 2 + pr = DISCUSSION_SERVICE.listPostReplies(topic, 5); + assertNotNull(pr); + assertEquals(post.getNodeRef(), pr.getNodeRef()); + assertEquals(2, pr.getReplies().size()); + + assertEquals(reply1.getNodeRef(), pr.getReplies().get(0).getNodeRef()); + assertEquals(reply2.getNodeRef(), pr.getReplies().get(1).getNodeRef()); + assertEquals(0, pr.getReplies().get(0).getReplies().size()); + assertEquals(0, pr.getReplies().get(1).getReplies().size()); + + + // Add a nesting of replies } } diff --git a/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java b/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java index 7b103c8744..99008065f5 100644 --- a/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java +++ b/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java @@ -31,8 +31,7 @@ import org.alfresco.repo.domain.node.NodeEntity; */ public class NodeWithTargetsEntity extends NodeBackedEntity { - private List targetIds; - private List targetAssocTypeIds; + private List targets; // Supplemental query-related parameters private Long assocTypeId; @@ -53,24 +52,17 @@ public class NodeWithTargetsEntity extends NodeBackedEntity this.assocTypeId = assocTypeId; } - public List getTargetIds() + /** + * @return Pairs of (Target Node, Assoc Type) + */ + public List getTargetIds() { - return targetIds; + return targets; } - public void setTargetIds(List targetIds) + public void setTargets(List targets) { - this.targetIds = targetIds; - } - - public List getTargetAssocTypeIds() - { - return targetAssocTypeIds; - } - - public void setTargetAssocTypeIds(List targetAssocTypeIds) - { - this.targetAssocTypeIds = targetAssocTypeIds; + this.targets = targets; } /** @@ -81,4 +73,26 @@ public class NodeWithTargetsEntity extends NodeBackedEntity { return assocTypeId; } + + public static class TargetAndTypeId + { + private final Long targetId; + private final Long assocTypeId; + + public TargetAndTypeId(Long targetId, Long assocTypeId) + { + this.targetId = targetId; + this.assocTypeId = assocTypeId; + } + + public Long getTargetId() + { + return targetId; + } + + public Long getAssocTypeId() + { + return assocTypeId; + } + } }