diff --git a/config/alfresco/discussions-services-context.xml b/config/alfresco/discussions-services-context.xml
index 8a716a667c..703cc1f9ba 100644
--- a/config/alfresco/discussions-services-context.xml
+++ b/config/alfresco/discussions-services-context.xml
@@ -49,8 +49,19 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml
index f88b627f7a..a54fcbf5bc 100644
--- a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml
+++ b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml
@@ -71,6 +71,7 @@ Inbound settings from iBatis
+
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 70f7154405..6adaf92bac 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
@@ -14,6 +14,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java b/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java
index 7177269fef..1d7b3abf1c 100644
--- a/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java
+++ b/source/java/org/alfresco/repo/discussion/DiscussionServiceImpl.java
@@ -36,7 +36,10 @@ import org.alfresco.query.PagingResults;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.node.getchildren.GetChildrenAuditableCannedQuery;
import org.alfresco.repo.node.getchildren.GetChildrenAuditableCannedQueryFactory;
+import org.alfresco.repo.node.getchildren.GetChildrenWithTargetAssocsAuditableCannedQuery;
+import org.alfresco.repo.node.getchildren.GetChildrenWithTargetAssocsAuditableCannedQueryFactory;
import org.alfresco.repo.query.NodeBackedEntity;
+import org.alfresco.repo.query.NodeWithTargetsEntity;
import org.alfresco.repo.site.SiteServiceImpl;
import org.alfresco.service.cmr.discussion.DiscussionService;
import org.alfresco.service.cmr.discussion.PostInfo;
@@ -67,6 +70,8 @@ public class DiscussionServiceImpl implements DiscussionService
public static final String DISCUSSION_COMPONENT = "discussions";
protected static final String CANNED_QUERY_GET_CHILDREN = "discussionGetChildrenCannedQueryFactory";
+ protected static final String CANNED_QUERY_GET_CHILDREN_TARGETS = "discussionGetChildrenWithTargetAssocsAuditableCannedQueryFactory";
+ protected static final int MAX_REPLIES_FETCH_SIZE = 1000;
/**
* The logger
@@ -588,7 +593,25 @@ public class DiscussionServiceImpl implements DiscussionService
@Override
public PostWithReplies listPostReplies(PostInfo primaryPost, int levels)
{
- // TODO Auto-generated method stub
+ // Grab the factory
+ GetChildrenWithTargetAssocsAuditableCannedQueryFactory cqFactory = (GetChildrenWithTargetAssocsAuditableCannedQueryFactory)cannedQueryRegistry.getNamedObject(CANNED_QUERY_GET_CHILDREN_TARGETS);
+
+ // Sort by date
+ CannedQuerySortDetails sorting = cqFactory.createDateAscendingCQSortDetails();
+
+ // Run the canned query
+ GetChildrenWithTargetAssocsAuditableCannedQuery cq = (GetChildrenWithTargetAssocsAuditableCannedQuery)cqFactory.getCannedQuery(
+ primaryPost.getTopic().getNodeRef(), ForumModel.TYPE_POST,
+ ContentModel.ASSOC_REFERENCES, sorting, new PagingRequest(MAX_REPLIES_FETCH_SIZE));
+
+ // Execute the canned query
+ CannedQueryResults results = cq.execute();
+
+ // Prepare to invert
+ // TODO
+ Map idToNode = new HashMap();
+
+ // All done
return null;
}
diff --git a/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java b/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java
index 470d003b4c..65b549a9a5 100644
--- a/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java
+++ b/source/java/org/alfresco/repo/discussion/DiscussionServiceImplTest.java
@@ -672,6 +672,24 @@ public class DiscussionServiceImplTest
}
}
+ /**
+ * Ensures that the listing / nesting of replies is correct
+ */
+ @Test public void replyListing() throws Exception
+ {
+ // Create two sites and test
+ TopicInfo siteT1 = DISCUSSION_SERVICE.createTopic(DISCUSSION_SITE.getShortName(), "ST1");
+ TopicInfo nodeT1 = DISCUSSION_SERVICE.createTopic(FORUM_NODE, "NT1");
+ testNodesToTidy.add(siteT1.getNodeRef());
+ testNodesToTidy.add(nodeT1.getNodeRef());
+
+ for(TopicInfo topic : new TopicInfo[] {siteT1, nodeT1})
+ {
+ // Listing initially gives nothing
+
+ }
+ }
+
/**
* Ensures that when we try to write an entry to the
* container of a new site, it is correctly setup for us.
diff --git a/source/java/org/alfresco/repo/node/getchildren/GetChildrenAuditableCannedQueryFactory.java b/source/java/org/alfresco/repo/node/getchildren/GetChildrenAuditableCannedQueryFactory.java
index 2749fb3f81..e7635271d3 100644
--- a/source/java/org/alfresco/repo/node/getchildren/GetChildrenAuditableCannedQueryFactory.java
+++ b/source/java/org/alfresco/repo/node/getchildren/GetChildrenAuditableCannedQueryFactory.java
@@ -18,9 +18,7 @@
*/
package org.alfresco.repo.node.getchildren;
-import java.util.ArrayList;
import java.util.Date;
-import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
@@ -29,12 +27,10 @@ import org.alfresco.query.CannedQueryPageDetails;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.CannedQuerySortDetails;
import org.alfresco.query.PagingRequest;
-import org.alfresco.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory;
import org.alfresco.repo.query.NodeBackedEntity;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
-import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
/**
@@ -91,22 +87,4 @@ public class GetChildrenAuditableCannedQueryFactory extends AbstractQNameAwareCa
// return canned query instance
return getCannedQuery(params);
}
-
- public CannedQuerySortDetails createDateAscendingCQSortDetails()
- {
- List> sort = new ArrayList>();
- sort.add(new Pair(ContentModel.PROP_CREATED, SortOrder.ASCENDING));
- sort.add(new Pair(ContentModel.PROP_MODIFIED, SortOrder.ASCENDING));
-
- return new CannedQuerySortDetails(sort);
- }
-
- public CannedQuerySortDetails createDateDescendingCQSortDetails()
- {
- List> sort = new ArrayList>();
- sort.add(new Pair(ContentModel.PROP_CREATED, SortOrder.DESCENDING));
- sort.add(new Pair(ContentModel.PROP_MODIFIED, SortOrder.DESCENDING));
-
- return new CannedQuerySortDetails(sort);
- }
}
diff --git a/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQuery.java b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQuery.java
new file mode 100644
index 0000000000..c79dbdddd7
--- /dev/null
+++ b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQuery.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.node.getchildren;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.alfresco.query.CannedQuery;
+import org.alfresco.query.CannedQueryParameters;
+import org.alfresco.query.CannedQuerySortDetails.SortOrder;
+import org.alfresco.repo.domain.query.CannedQueryDAO;
+import org.alfresco.repo.query.NodeBackedEntity;
+import org.alfresco.repo.query.NodeWithTargetsEntity;
+import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory.NestedComparator;
+import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory.NodeBackedEntityComparator;
+import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
+import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityBean;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.Pair;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class provides support for {@link CannedQuery canned queries} which
+ * filter by Auditable Properties and Target Assocs
+ *
+ * @author Nick Burch
+ * @since 4.0
+ */
+public class GetChildrenWithTargetAssocsAuditableCannedQuery extends AbstractCannedQueryPermissions
+{
+ private Log logger = LogFactory.getLog(getClass());
+
+ private static final String QUERY_NAMESPACE = "alfresco.query.auditable";
+ private static final String QUERY_SELECT_GET_NODES = "select_GetChildrenWithTargetAssocsAuditableCannedQuery";
+
+ private final CannedQueryDAO cannedQueryDAO;
+
+ public GetChildrenWithTargetAssocsAuditableCannedQuery(
+ CannedQueryDAO cannedQueryDAO,
+ MethodSecurityBean methodSecurity,
+ CannedQueryParameters params)
+ {
+ super(params, methodSecurity);
+ this.cannedQueryDAO = cannedQueryDAO;
+ }
+
+ @Override
+ protected List queryAndFilter(CannedQueryParameters parameters)
+ {
+ Long start = (logger.isDebugEnabled() ? System.currentTimeMillis() : null);
+
+ Object paramBeanObj = parameters.getParameterBean();
+ if (paramBeanObj == null)
+ throw new NullPointerException("Null GetChildrenWithTargetAssocsAuditable query params");
+
+ GetChildrenWithTargetAssocsAuditableCannedQueryParams paramBean = (GetChildrenWithTargetAssocsAuditableCannedQueryParams) paramBeanObj;
+
+ // note: refer to SQL for specific DB filtering (eg.parent nodes etc)
+ List results = cannedQueryDAO.executeQuery(QUERY_NAMESPACE, QUERY_SELECT_GET_NODES, paramBean, 0, Integer.MAX_VALUE);
+
+ List filtered = new ArrayList(results.size());
+ for (NodeWithTargetsEntity result : results)
+ {
+ boolean nextNodeIsAcceptable = true;
+
+ // Note - all filtering is currently done in the database
+
+ // Did it make the cut
+ if (nextNodeIsAcceptable)
+ {
+ filtered.add(result);
+ }
+ }
+
+ List> sortPairs = parameters.getSortDetails().getSortPairs();
+
+ // Do the sorting
+ if (sortPairs != null && !sortPairs.isEmpty())
+ {
+ List, SortOrder>> comparators =
+ new ArrayList,SortOrder>>();
+ for(Pair extends Object, SortOrder> sortPair : sortPairs)
+ {
+ final QName sortProperty = (QName)sortPair.getFirst();
+ final NodeBackedEntityComparator comparator = new NodeBackedEntityComparator(sortProperty);
+ comparators.add(new Pair, SortOrder>(comparator, sortPair.getSecond()));
+ }
+ NestedComparator comparator = new NestedComparator(comparators);
+
+ // Sort
+ Collections.sort(filtered, comparator);
+ }
+
+ if (start != null)
+ {
+ logger.debug("Base query: "+filtered.size()+" in "+(System.currentTimeMillis()-start)+" msecs");
+ }
+
+ return filtered;
+ }
+
+ @Override
+ protected boolean isApplyPostQuerySorting()
+ {
+ // No post-query sorting. It's done within the queryAndFilter() method above.
+ return false;
+ }
+}
diff --git a/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryFactory.java b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryFactory.java
new file mode 100644
index 0000000000..7788a6e3dc
--- /dev/null
+++ b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryFactory.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.node.getchildren;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.query.CannedQuery;
+import org.alfresco.query.CannedQueryFactory;
+import org.alfresco.query.CannedQueryPageDetails;
+import org.alfresco.query.CannedQueryParameters;
+import org.alfresco.query.CannedQuerySortDetails;
+import org.alfresco.query.PagingRequest;
+import org.alfresco.repo.query.AbstractQNameAwareCannedQueryFactory;
+import org.alfresco.repo.query.NodeWithTargetsEntity;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.ParameterCheck;
+
+/**
+ * A {@link CannedQueryFactory} for various queries relating to getting
+ * {@link NodeWithTargetsEntity} entires filtering by auditable properties.
+ *
+ * @author Nick Burch
+ * @since 4.0
+ */
+public class GetChildrenWithTargetAssocsAuditableCannedQueryFactory extends AbstractQNameAwareCannedQueryFactory
+{
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+ }
+
+ @Override
+ public CannedQuery getCannedQuery(CannedQueryParameters parameters)
+ {
+ final GetChildrenWithTargetAssocsAuditableCannedQuery cq = new GetChildrenWithTargetAssocsAuditableCannedQuery(
+ cannedQueryDAO, methodSecurity, parameters
+ );
+
+ return (CannedQuery) cq;
+ }
+
+ public CannedQuery getCannedQuery(NodeRef parentNodeRef,
+ QName contentType, QName assocType,
+ CannedQuerySortDetails sortDetails, PagingRequest pagingReq)
+ {
+ ParameterCheck.mandatory("parentNodeRef", parentNodeRef);
+ ParameterCheck.mandatory("contentType", contentType);
+ ParameterCheck.mandatory("pagingReq", pagingReq);
+
+ int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
+
+ //FIXME Need tenant service like for GetChildren?
+ GetChildrenWithTargetAssocsAuditableCannedQueryParams paramBean = new GetChildrenWithTargetAssocsAuditableCannedQueryParams(
+ getNodeId(parentNodeRef),
+ getQNameId(ContentModel.PROP_NAME),
+ getQNameId(contentType),
+ getQNameId(assocType)
+ );
+
+ CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
+
+ // create query params holder
+ CannedQueryParameters params = new CannedQueryParameters(
+ paramBean, cqpd, sortDetails, requestTotalCountMax, pagingReq.getQueryExecutionId());
+
+ // return canned query instance
+ return getCannedQuery(params);
+ }
+}
diff --git a/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryParams.java b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryParams.java
new file mode 100644
index 0000000000..bfad079b51
--- /dev/null
+++ b/source/java/org/alfresco/repo/node/getchildren/GetChildrenWithTargetAssocsAuditableCannedQueryParams.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.node.getchildren;
+
+import org.alfresco.repo.query.NodeWithTargetsEntity;
+
+/**
+ * Parameter objects for {@link GetChildrenWithTargetAssocsAuditableCannedQuery}.
+ *
+ * @author Nick Burch
+ * @since 4.0
+ */
+public class GetChildrenWithTargetAssocsAuditableCannedQueryParams extends NodeWithTargetsEntity
+{
+ public GetChildrenWithTargetAssocsAuditableCannedQueryParams(Long parentNodeId,
+ Long nameQNameId,
+ Long contentTypeQNameId,
+ Long assocTypeId)
+
+ {
+ super(parentNodeId, nameQNameId, contentTypeQNameId, assocTypeId);
+ }
+}
diff --git a/source/java/org/alfresco/repo/query/AbstractQNameAwareCannedQueryFactory.java b/source/java/org/alfresco/repo/query/AbstractQNameAwareCannedQueryFactory.java
index 366abb630c..463ad81d16 100644
--- a/source/java/org/alfresco/repo/query/AbstractQNameAwareCannedQueryFactory.java
+++ b/source/java/org/alfresco/repo/query/AbstractQNameAwareCannedQueryFactory.java
@@ -155,6 +155,24 @@ public abstract class AbstractQNameAwareCannedQueryFactory extends AbstractCa
return nodePair.getFirst();
}
+ public CannedQuerySortDetails createDateAscendingCQSortDetails()
+ {
+ List> sort = new ArrayList>();
+ sort.add(new Pair(ContentModel.PROP_CREATED, SortOrder.ASCENDING));
+ sort.add(new Pair(ContentModel.PROP_MODIFIED, SortOrder.ASCENDING));
+
+ return new CannedQuerySortDetails(sort);
+ }
+
+ public CannedQuerySortDetails createDateDescendingCQSortDetails()
+ {
+ List> sort = new ArrayList>();
+ sort.add(new Pair(ContentModel.PROP_CREATED, SortOrder.DESCENDING));
+ sort.add(new Pair(ContentModel.PROP_MODIFIED, SortOrder.DESCENDING));
+
+ return new CannedQuerySortDetails(sort);
+ }
+
/**
* Utility class to sort Entities on the basis of a Comparable property.
* Comparisons of two null properties are considered 'equal' by this comparator.
@@ -212,6 +230,7 @@ public abstract class AbstractQNameAwareCannedQueryFactory extends AbstractCa
super(comparableProperty);
}
+ @SuppressWarnings("unchecked")
@Override
protected Comparable getProperty(NodeBackedEntity entity) {
if (comparableProperty.equals(ContentModel.PROP_CREATED))
diff --git a/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java b/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java
new file mode 100644
index 0000000000..7b103c8744
--- /dev/null
+++ b/source/java/org/alfresco/repo/query/NodeWithTargetsEntity.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2005-2011 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.query;
+
+import java.util.List;
+
+import org.alfresco.repo.domain.node.NodeEntity;
+
+/**
+ * Parent class of Canned Query Entities which are a
+ * {@link NodeEntity} with additional properties
+ *
+ * @author Nick Burch
+ * @since 4.0
+ */
+public class NodeWithTargetsEntity extends NodeBackedEntity
+{
+ private List targetIds;
+ private List targetAssocTypeIds;
+
+ // Supplemental query-related parameters
+ private Long assocTypeId;
+
+ /**
+ * Default constructor
+ */
+ public NodeWithTargetsEntity()
+ {
+ }
+
+ /**
+ * Query constructor
+ */
+ public NodeWithTargetsEntity(Long parentNodeId, Long nameQNameId, Long contentTypeQNameId, Long assocTypeId)
+ {
+ super(parentNodeId, nameQNameId, contentTypeQNameId);
+ this.assocTypeId = assocTypeId;
+ }
+
+ public List getTargetIds()
+ {
+ return targetIds;
+ }
+
+ public void setTargetIds(List targetIds)
+ {
+ this.targetIds = targetIds;
+ }
+
+ public List getTargetAssocTypeIds()
+ {
+ return targetAssocTypeIds;
+ }
+
+ public void setTargetAssocTypeIds(List targetAssocTypeIds)
+ {
+ this.targetAssocTypeIds = targetAssocTypeIds;
+ }
+
+ /**
+ * If set, the ID of the assocation type to limit
+ * the target assocs to.
+ */
+ public Long getAssocTypeId()
+ {
+ return assocTypeId;
+ }
+}