Merged BRANCHES/DEV/SWIFT to HEAD:

28466: Fix for ALF-6541. maintainAspectRatio does not default to true as documented.
        Fixed the javadoc to reflect reality.

Merged BRANCHES/DEV/SWIFT to HEAD:
   28482 Implementation of ALF-8969 Lucene removal: Blog webscripts.
        ** Checking this in on Swift branch, as I have the work there. Will merge to HEAD.

        The blog webscript controllers have been ported from JavaScript to Java.
        A new foundation service, the BlogService has been added and the impls of the webscript controllers delegate into that service, thus encapsulating business logic within the service.
        The API for this service is based on the requirements of the existing webscripts, but is for the most part a 'sensible' API. One controller (blogposts.get.js) had very domain-specific requirements (get all of my drafts and all published posts) and it is implemented as a deprecated public method on the service.
        The API is not complete, but represents a good starting point for any future feature development.
        The various Lucene queries have been replaced with calls to the nodeservice (as an impl detail within the BlogService) which get all blog post nodes and then post-filter them based on property values, aspect/property presence etc. This will       be refactored into a CannedQuery in a subsequent check-in.
 
        I've written new test cases aimed at this API & have extended the REST API tests.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28483 Prevent NPEs in some circumstances. Related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28484 Fixing activity reports for Blog posting. Following on from previous chagnes related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28597 ALF-8969. Introduction of brute force Canned Queries for BlogService query methods.
        This will be merged to HEAD after a chat with Jan/Derek.

        Introduced 'brute force' Canned Queries for the various BlogService query methods.
          These use the underlying nodeService to retrieve result sets.
          They must use the small-n nodeService in order to get full result sets.
          Therefore I have had to add some AFTER_ACL_ENTRY checks to the BlogService_security bean for the query methods.
        Added various CannedQuery classes for the BlogService queries. They currently split into two:
          1. a GetBlogPostsCannedQuery which goes some way towards providing configurable query support, albeit driven by the needs of the Blog Service REST API.
          2. a DraftsAndPublishedBlogPostsCannedQuery, which is a very specific CQ aimed at a very specific scenario in the REST API.
        Changed the BlogService API to return a BlogPostInfo (simple POJO) rather than the less extensible NodeRef.
          This affected the webscript implementations.
        Added BlogPostInfo as an acceptable return type for security-based filtering in ACLEntryAfterInvocationProvider.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28598 Repackaged the CannedQuery-related classes to a dedicated subpackage. ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28602 Replacement of some JS controllers with Java-based ports. Part of ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28603 Disabling two test cases pending a refactoring. Related to ALF-8969.

Merged BRANCHES/DEV/SWIFT to HEAD:
   r28604 Fixing a compilation error.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28606 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2011-06-27 10:10:07 +00:00
parent 61a68effa5
commit ce540080f7
27 changed files with 3460 additions and 4 deletions

View File

@@ -2,8 +2,107 @@
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<!-- Blog Integration Service -->
<!-- Blog Service (Alfresco internal storage of blog-related content) -->
<bean id="BlogService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.repo.blog.BlogService</value>
</property>
<property name="target">
<ref bean="blogService" />
</property>
<property name="interceptorNames">
<list>
<idref local="BlogService_transaction" />
<idref bean="AuditMethodInterceptor" />
<idref bean="exceptionTranslator" />
<idref local="BlogService_security" />
</list>
</property>
</bean>
<!-- Blog service transaction bean -->
<bean id="BlogService_transaction"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">${server.transaction.mode.default}</prop>
</props>
</property>
</bean>
<bean id="BlogService_security" class="org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref bean="accessDecisionManager"/></property>
<property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property>
<property name="objectDefinitionSource">
<value>
<!-- ACL_NODE.0 means you need the following permissions on a NodeRef method-arg at index 0. -->
<!-- AFTER_ACL_NODE means you need the specified permissions on the return type,
type must be one of ChAssRef, FileInfo, NodeRef, StoreRef, ResultSet & Collections, arrays of same -->
org.alfresco.repo.blog.BlogService.getDrafts=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.repo.blog.BlogService.getPublished=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.repo.blog.BlogService.getPublishedExternally=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.repo.blog.BlogService.getMyDraftsAndAllPublished=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.ReadProperties
org.alfresco.repo.blog.BlogService.*=ACL_ALLOW
</value>
</property>
</bean>
<!-- Blog Service base bean -->
<bean id="blogService" class="org.alfresco.repo.blog.BlogServiceImpl">
<property name="cannedQueryRegistry" ref="cannedQueryRegistry"/>
<property name="contentService" ref="ContentService"/>
<property name="nodeService" ref="NodeService"/>
<property name="permissionService" ref="PermissionService"/>
<property name="taggingService" ref="TaggingService"/>
<property name="draftBlogPostsCannedQueryFactory" ref="getDraftBlogPostsCannedQueryFactory"/>
<property name="publishedBlogPostsCannedQueryFactory" ref="getPublishedBlogPostsCannedQueryFactory"/>
<property name="publishedExternallyBlogPostsCannedQueryFactory" ref="getPublishedExternallyBlogPostsCannedQueryFactory"/>
<property name="draftsAndPublishedBlogPostsCannedQueryFactory" ref="getDraftsAndPublishedBlogPostsCannedQueryFactory"/>
</bean>
<!-- Canned Queries -->
<!-- We currently need one CQFactory per CQ in order to support interception at each of the different methods -->
<!-- TODO Check with Jan/Derek -->
<bean name="parentBlogPostsCannedQueryFactory" abstract="true">
<property name="registry" ref="cannedQueryRegistry"/>
<property name="methodSecurityInterceptor" ref="BlogService_security"/>
<property name="methodService" ref="blogService"/>
<!-- Intentionally injecting the small 'n', undecorated NodeService. -->
<property name="rawNodeService" ref="nodeService"/>
</bean>
<bean name="getDraftBlogPostsCannedQueryFactory" parent="parentBlogPostsCannedQueryFactory"
class="org.alfresco.repo.blog.cannedqueries.GetBlogPostsCannedQueryFactory">
<property name="methodName" value="getDrafts"/>
</bean>
<bean name="getPublishedExternallyBlogPostsCannedQueryFactory" parent="parentBlogPostsCannedQueryFactory"
class="org.alfresco.repo.blog.cannedqueries.GetBlogPostsCannedQueryFactory">
<property name="methodName" value="getPublishedExternally"/>
</bean>
<bean name="getPublishedBlogPostsCannedQueryFactory" parent="parentBlogPostsCannedQueryFactory"
class="org.alfresco.repo.blog.cannedqueries.GetBlogPostsCannedQueryFactory">
<property name="methodName" value="getPublished"/>
</bean>
<bean name="getDraftsAndPublishedBlogPostsCannedQueryFactory" parent="parentBlogPostsCannedQueryFactory"
class="org.alfresco.repo.blog.cannedqueries.DraftsAndPublishedBlogPostsCannedQueryFactory">
<property name="methodName" value="getMyDraftsAndAllPublished"/>
<property name="taggingService" ref="TaggingService"/>
</bean>
<!-- Blog Integration Service (Integration with external blog hosting sites) -->
<bean id="BlogIntegrationService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">

View File

@@ -0,0 +1,42 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* A simple data object for storage of blog-related data.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public interface BlogPostInfo
{
/**
* Gets the NodeRef representing this blog-post.
*/
public NodeRef getNodeRef();
/**
* Gets the {@link ContentModel#PROP_NAME cm:name} of the blog post.
* @return
*/
public String getName();
}

View File

@@ -0,0 +1,101 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* A simple data object responsible for holding information relevant to blog post NodeRefs.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class BlogPostInfoImpl implements BlogPostInfo
{
private NodeRef nodeRef;
private Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
BlogPostInfoImpl(NodeRef nodeRef, Map<QName, Serializable> properties)
{
this.nodeRef = nodeRef;
this.properties = properties;
}
/**
* @see #getNodeRef()
* @see NodeRef#equals(Object)
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
else if (this == obj)
{
return true;
}
else if (obj instanceof BlogPostInfoImpl == false)
{
return false;
}
BlogPostInfoImpl that = (BlogPostInfoImpl) obj;
return (this.getNodeRef().equals(that.getNodeRef()));
}
/**
* @see #getNodeRef()
* @see NodeRef#hashCode()
*/
@Override
public int hashCode()
{
return getNodeRef().hashCode();
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(80);
sb.append(BlogPostInfo.class.getSimpleName())
.append("[name=").append(getName())
.append(", nodeRef=").append(nodeRef);
sb.append("]");
return sb.toString();
}
@Override
public NodeRef getNodeRef()
{
return nodeRef;
}
@Override
public String getName()
{
return (String) properties.get(ContentModel.PROP_NAME);
}
}

View File

@@ -0,0 +1,122 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.util.Date;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.site.SiteService;
/**
* The Blog Service handles the management (CRUD) of Alfresco blog data, namely the blog posts which are
* exposed in the Share UI under the "Blog" heading. The {@link BlogIntegrationService}, a separate service, is
* concerned with the integration of Alfresco blog content with external Blog-hosting sites.
* <p/>
* Please note that this service is a work in progress and currently exists primarily to support the blogs REST API.
*
* @author Neil Mc Erlean (based on existing webscript controllers in the REST API)
* @since 4.0
*/
public interface BlogService
{
/**
* Creates a new blog post within the specified container node.
*
* @param blogContainerNode the container node for blog posts (under the site).
* @param blogTitle the title of the blog post.
* @param blogContent text/html content of the blog post.
* @param isDraft <tt>true</tt> if the blog post is a draft post, else <tt>false</tt>.
*
* @return The {@link ChildAssociationRef} of the newly created blog post.
*
* @see SiteService#getContainer(String, String) to retrieve the blogContainerNode
*/
ChildAssociationRef createBlogPost(NodeRef blogContainerNode, String blogTitle,
String blogContent, boolean isDraft);
/**
* Gets the draft blog posts created by the specified user.
*
* @param blogContainerNode the container node for blog posts (under the site).
* @param username to limit results to blogs with this cm:creator. <tt>null</tt> means all users.
* @param pagingReq an object defining the paging parameters for the result set.
*
* @return a {@link PagingResults} object containing some or all of the results (subject to paging).
*
* @see SiteService#getContainer(String, String) to retrieve the blogContainerNode
*/
PagingResults<BlogPostInfo> getDrafts(NodeRef blogContainerNode, String username, PagingRequest pagingReq);
/**
* Gets the (internally, Alfresco-) published blog posts.
*
* @param blogContainerNode the container node for blog posts (under the site).
* @param fromDate an inclusive date limit for the results (more recent than).
* @param toDate an inclusive date limit for the results (before).
* @param byUser if not <tt>null</tt> limits results to posts by the specified user.
* if <tt>null</tt> results will be by all users.
* @param pagingReq an object defining the paging parameters for the result set.
*
* @return a {@link PagingResults} object containing some or all of the results (subject to paging).
*
* @see SiteService#getContainer(String, String) to retrieve the blogContainerNode
*/
PagingResults<BlogPostInfo> getPublished(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, PagingRequest pagingReq);
/**
* Gets blog posts published externally (i.e. to an external blog hosting site).
*
* @param blogContainerNode the container node for blog posts (under the site).
* @param pagingReq an object defining the paging parameters for the result set.
*
* @return a {@link PagingResults} object containing some or all of the results (subject to paging).
*
* @see SiteService#getContainer(String, String) to retrieve the blogContainerNode
*/
PagingResults<BlogPostInfo> getPublishedExternally(NodeRef blogContainerNode, PagingRequest pagingReq);
/**
* Gets draft blog posts by the currently authenticated user along with all published posts.
*
* @param blogContainerNode the container node for blog posts (under the site).
* @param fromDate an inclusive date limit for the results (more recent than).
* @param toDate an inclusive date limit for the results (before).
* @param tag if specified, only returns posts tagged with this tag.
* @param pagingReq an object defining the paging parameters for the result set.
*
* @return a {@link PagingResults} object containing some or all of the results (subject to paging).
*
* @see SiteService#getContainer(String, String) to retrieve the blogContainerNode
*
* @deprecated This method is a domain-specific query used by the Blog REST API and is not considered suitable for general use.
*/
PagingResults<BlogPostInfo> getMyDraftsAndAllPublished(NodeRef blogContainerNode, Date fromDate, Date toDate,
String tag, PagingRequest pagingReq);
/**
* Returns true if the specified blog-post node is a 'draft' blog post.
*
* @param blogPostNode a NodeRef representing a blog-post.
* @return <tt>true</tt> if it is a draft post, else <tt>false</tt>.
*/
boolean isDraftBlogPost(NodeRef blogPostNode);
}

View File

@@ -0,0 +1,316 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQueryFactory;
import org.alfresco.query.CannedQueryResults;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.blog.cannedqueries.DraftsAndPublishedBlogPostsCannedQuery;
import org.alfresco.repo.blog.cannedqueries.DraftsAndPublishedBlogPostsCannedQueryFactory;
import org.alfresco.repo.blog.cannedqueries.GetBlogPostsCannedQuery;
import org.alfresco.repo.blog.cannedqueries.GetBlogPostsCannedQueryFactory;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.registry.NamedObjectRegistry;
/**
* @author Neil Mc Erlean (based on existing webscript controllers in the REST API)
* @since 4.0
*/
public class BlogServiceImpl implements BlogService
{
/**
* For backwards compatibility with pre-Swift, we are asking the query to give us an accurate total count of how many
* blog-post nodes there are. This may need to change in the future - certainly if the current 'brute force' query
* is replaced by a database query.
*/
private static final int MAX_QUERY_ENTRY_COUNT = 10000;
// Injected services
private NamedObjectRegistry<CannedQueryFactory<BlogPostInfo>> cannedQueryRegistry;
private GetBlogPostsCannedQueryFactory draftPostsCannedQueryFactory;
private GetBlogPostsCannedQueryFactory publishedPostsCannedQueryFactory;
private GetBlogPostsCannedQueryFactory publishedExternallyPostsCannedQueryFactory;
private DraftsAndPublishedBlogPostsCannedQueryFactory draftsAndPublishedBlogPostsCannedQueryFactory;
private ContentService contentService;
private NodeService nodeService;
private PermissionService permissionService;
private TaggingService taggingService;
public void setCannedQueryRegistry(NamedObjectRegistry<CannedQueryFactory<BlogPostInfo>> cannedQueryRegistry)
{
this.cannedQueryRegistry = cannedQueryRegistry;
}
public void setDraftBlogPostsCannedQueryFactory(GetBlogPostsCannedQueryFactory cannedQueryFactory)
{
this.draftPostsCannedQueryFactory = cannedQueryFactory;
}
public void setPublishedBlogPostsCannedQueryFactory(GetBlogPostsCannedQueryFactory cannedQueryFactory)
{
this.publishedPostsCannedQueryFactory = cannedQueryFactory;
}
public void setPublishedExternallyBlogPostsCannedQueryFactory(GetBlogPostsCannedQueryFactory cannedQueryFactory)
{
this.publishedExternallyPostsCannedQueryFactory = cannedQueryFactory;
}
public void setDraftsAndPublishedBlogPostsCannedQueryFactory(DraftsAndPublishedBlogPostsCannedQueryFactory cannedQueryFactory)
{
this.draftsAndPublishedBlogPostsCannedQueryFactory = cannedQueryFactory;
}
public void setContentService(ContentService contentService)
{
this.contentService = contentService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.blog.BlogService#isDraftBlogPost(org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
public boolean isDraftBlogPost(NodeRef blogPostNode)
{
return nodeService.getProperty(blogPostNode, ContentModel.PROP_PUBLISHED) == null;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.blog.BlogService#createBlogPost(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, java.util.List, boolean)
*/
@Override
public ChildAssociationRef createBlogPost(NodeRef blogContainerNode, String blogTitle,
String blogContent, boolean isDraft)
{
String nodeName = getUniqueChildName(blogContainerNode, "post");
// we simply create a new file inside the blog folder
Map<QName, Serializable> nodeProps = new HashMap<QName, Serializable>();
nodeProps.put(ContentModel.PROP_NAME, nodeName);
nodeProps.put(ContentModel.PROP_TITLE, blogTitle);
QName assocName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nodeName);
ChildAssociationRef postNode = nodeService.createNode(blogContainerNode, ContentModel.ASSOC_CONTAINS, assocName,
ContentModel.TYPE_CONTENT, nodeProps);
ContentWriter writer = contentService.getWriter(postNode.getChildRef(), ContentModel.PROP_CONTENT, true);
// Blog posts are always HTML (based on the JavaScript this class replaces.)
writer.setMimetype(MimetypeMap.MIMETYPE_HTML);
writer.setEncoding("UTF-8");
writer.putContent(blogContent);
if (isDraft)
{
// Comment from the old JavaScript:
// disable permission inheritance. The result is that only the creator will have access to the draft
permissionService.setInheritParentPermissions(postNode.getChildRef(), false);
}
else
{
setOrUpdateReleasedAndUpdatedDates(postNode.getChildRef());
}
return postNode;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.blog.BlogService#getMyDrafts(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.query.PagingRequest)
*/
@Override
public PagingResults<BlogPostInfo> getDrafts(NodeRef blogContainerNode, String username, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
// get canned query
pagingReq.setRequestTotalCountMax(MAX_QUERY_ENTRY_COUNT);
GetBlogPostsCannedQuery cq = (GetBlogPostsCannedQuery)draftPostsCannedQueryFactory.getGetDraftsCannedQuery(blogContainerNode, username, pagingReq);
// execute canned query
CannedQueryResults<BlogPostInfo> results = cq.execute();
return createPagedResults(pagingReq, results);
}
/**
* This method creates a paged result set based on the supplied {@link PagingRequest} and {@link CannedQueryResults}.
*/
private PagingResults<BlogPostInfo> createPagedResults(PagingRequest pagingReq, CannedQueryResults<BlogPostInfo> results)
{
List<BlogPostInfo> nodeRefs = null;
if (results.getPageCount() > 0)
{
nodeRefs = results.getPages().get(0);
}
else
{
nodeRefs = Collections.emptyList();
}
// set total count
Pair<Integer, Integer> totalCount = null;
if (pagingReq.getRequestTotalCountMax() > 0)
{
totalCount = results.getTotalResultCount();
}
boolean hasMoreItems = results.hasMoreItems();
return new PagingBlogPostInfoResultsImpl(nodeRefs, hasMoreItems, totalCount, results.getQueryExecutionId(), true);
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.blog.BlogService#getPublishedExternally(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.query.PagingRequest)
*/
@Override
public PagingResults<BlogPostInfo> getPublishedExternally(NodeRef blogContainerNode, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
// get canned query
pagingReq.setRequestTotalCountMax(MAX_QUERY_ENTRY_COUNT);
GetBlogPostsCannedQuery cq = (GetBlogPostsCannedQuery)publishedExternallyPostsCannedQueryFactory.getGetPublishedExternallyCannedQuery(blogContainerNode, pagingReq);
// execute canned query
CannedQueryResults<BlogPostInfo> results = cq.execute();
return createPagedResults(pagingReq, results);
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.blog.BlogService#getPublished(org.alfresco.service.cmr.repository.NodeRef, java.util.Date, java.util.Date, java.lang.String, org.alfresco.query.PagingRequest)
*/
@Override
public PagingResults<BlogPostInfo> getPublished(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
// get canned query
pagingReq.setRequestTotalCountMax(MAX_QUERY_ENTRY_COUNT);
GetBlogPostsCannedQuery cq = (GetBlogPostsCannedQuery)publishedPostsCannedQueryFactory.getGetPublishedCannedQuery(blogContainerNode, fromDate, toDate, byUser, pagingReq);
// execute canned query
CannedQueryResults<BlogPostInfo> results = cq.execute();
return createPagedResults(pagingReq, results);
}
/**
* @deprecated
*/
@Override
public PagingResults<BlogPostInfo> getMyDraftsAndAllPublished(NodeRef blogContainerNode, Date createdFrom, Date createdTo, String tag, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
// get canned query
pagingReq.setRequestTotalCountMax(MAX_QUERY_ENTRY_COUNT);
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
DraftsAndPublishedBlogPostsCannedQuery cq = (DraftsAndPublishedBlogPostsCannedQuery)draftsAndPublishedBlogPostsCannedQueryFactory.getCannedQuery(blogContainerNode, createdFrom, createdTo, currentUser, tag, pagingReq);
// execute canned query
CannedQueryResults<BlogPostInfo> results = cq.execute();
return createPagedResults(pagingReq, results);
}
private String getUniqueChildName(NodeRef parentNode, String prefix)
{
return prefix + "-" + System.currentTimeMillis();
}
/**
* This method is taken from the previous JavaScript webscript controllers.
* @param blogPostNode
*/
private void setOrUpdateReleasedAndUpdatedDates(NodeRef blogPostNode)
{
// make sure the syndication aspect has been added
if (!nodeService.hasAspect(blogPostNode, ContentModel.ASPECT_SYNDICATION))
{
nodeService.addAspect(blogPostNode, ContentModel.ASPECT_SYNDICATION, null);
}
// (re-)enable permission inheritance which got disable for draft posts
// only set if was previously draft - as only the owner/admin can do this
if (!permissionService.getInheritParentPermissions(blogPostNode))
{
permissionService.setInheritParentPermissions(blogPostNode, true);
}
// check whether the published date has been set
if (nodeService.getProperty(blogPostNode, ContentModel.PROP_PUBLISHED) == null)
{
nodeService.setProperty(blogPostNode, ContentModel.PROP_PUBLISHED, new Date());
}
else
{
// set/update the updated date
nodeService.setProperty(blogPostNode, ContentModel.PROP_UPDATED, new Date());
}
}
}

View File

@@ -0,0 +1,540 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyMap;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
/**
* Test cases for {@link BlogServiceImpl}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class BlogServiceImplTest
{
private static final ApplicationContext testContext = ApplicationContextHelper.getApplicationContext();
// injected services
private static MutableAuthenticationService AUTHENTICATION_SERVICE;
private static BehaviourFilter BEHAVIOUR_FILTER;
private static BlogService BLOG_SERVICE;
private static DictionaryService DICTIONARY_SERVICE;
private static NodeService NODE_SERVICE;
private static PersonService PERSON_SERVICE;
private static RetryingTransactionHelper TRANSACTION_HELPER;
private static SiteService SITE_SERVICE;
private static TaggingService TAGGING_SERVICE;
private static final String TEST_USER = BlogServiceImplTest.class.getSimpleName() + "_testuser";
private static final String ADMIN_USER = AuthenticationUtil.getAdminUserName();
/**
* Temporary test nodes (created during a test method) that need deletion after the test method.
*/
private List<NodeRef> testNodesToTidy = new ArrayList<NodeRef>();
/**
* Temporary test nodes (created BeforeClass) that need deletion after this test class.
*/
private static List<NodeRef> CLASS_TEST_NODES_TO_TIDY = new ArrayList<NodeRef>();
private static NodeRef BLOG_CONTAINER_NODE;
@BeforeClass public static void initTestsContext() throws Exception
{
AUTHENTICATION_SERVICE = (MutableAuthenticationService)testContext.getBean("authenticationService");
BEHAVIOUR_FILTER = (BehaviourFilter)testContext.getBean("policyBehaviourFilter");
BLOG_SERVICE = (BlogService)testContext.getBean("blogService");
DICTIONARY_SERVICE = (DictionaryService)testContext.getBean("dictionaryService");
NODE_SERVICE = (NodeService)testContext.getBean("nodeService");
PERSON_SERVICE = (PersonService)testContext.getBean("personService");
TRANSACTION_HELPER = (RetryingTransactionHelper)testContext.getBean("retryingTransactionHelper");
SITE_SERVICE = (SiteService)testContext.getBean("siteService");
TAGGING_SERVICE = (TaggingService)testContext.getBean("TaggingService");
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
createUser(TEST_USER);
// We need to create the test site as the test user so that they can contribute content to it in tests below.
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER);
createTestSiteWithBlogContainer();
}
private static void createTestSiteWithBlogContainer() throws Exception
{
BLOG_CONTAINER_NODE = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
@Override
public NodeRef execute() throws Throwable
{
SiteInfo site = SITE_SERVICE.createSite("BlogSitePreset", BlogServiceImplTest.class.getSimpleName() + "_testSite" + System.currentTimeMillis(),
"test site title", "test site description", SiteVisibility.PUBLIC);
CLASS_TEST_NODES_TO_TIDY.add(site.getNodeRef());
NodeRef result = SITE_SERVICE.getContainer(site.getShortName(), "blog");
if (result == null)
{
result = NODE_SERVICE.createNode(site.getNodeRef(), ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "blog"), ContentModel.TYPE_FOLDER, null).getChildRef();
CLASS_TEST_NODES_TO_TIDY.add(result);
}
return result;
}
});
}
/**
* By default, all tests are run as the admin user.
*/
@Before public void setAdminUser()
{
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
}
@After public void deleteTestNodes() throws Exception
{
performDeletionOfNodes(testNodesToTidy);
}
@AfterClass public static void deleteClassTestNodesAndUsers() throws Exception
{
performDeletionOfNodes(CLASS_TEST_NODES_TO_TIDY);
deleteUser(TEST_USER);
}
/**
* Deletes the specified NodeRefs, if they exist.
* @param nodesToDelete
*/
private static void performDeletionOfNodes(final List<NodeRef> nodesToDelete)
{
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
for (NodeRef node : nodesToDelete)
{
if (NODE_SERVICE.exists(node)) NODE_SERVICE.deleteNode(node);
}
return null;
}
});
}
@Test public void createDraftBlogPostsAndGetPagedResults() throws Exception
{
final int arbitraryNumberGreaterThanPageSize = 42;
final List<NodeRef> submittedBlogPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<List<NodeRef>>()
{
@Override
public List<NodeRef> execute() throws Throwable
{
List<NodeRef> results = new ArrayList<NodeRef>();
for (int i = 0; i < arbitraryNumberGreaterThanPageSize; i++)
{
ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "title_" + i, "Hello world", true);
results.add(newBlogPost.getChildRef());
testNodesToTidy.add(newBlogPost.getChildRef());
}
return results;
}
});
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
List<BlogPostInfo> recoveredBlogPosts = new ArrayList<BlogPostInfo>(arbitraryNumberGreaterThanPageSize);
final int pageSize = 10;
PagingRequest pagingReq = new PagingRequest(0, pageSize, null);
PagingResults<BlogPostInfo> pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq);
assertEquals("Wrong total result count.", arbitraryNumberGreaterThanPageSize, (int)pagedResults.getTotalResultCount().getFirst());
while (pagedResults.hasMoreItems())
{
recoveredBlogPosts.addAll(pagedResults.getPage());
pagingReq = new PagingRequest(pagingReq.getSkipCount() + pageSize, pageSize, null);
pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq);
}
// and the last page, which only has 2 items in it.
recoveredBlogPosts.addAll(pagedResults.getPage());
assertEquals("Wrong number of blog posts.", submittedBlogPosts.size(), recoveredBlogPosts.size());
// Check the list is sorted by cm:created, descending order.
assertNodeRefsAreSortedBy(recoveredBlogPosts, ContentModel.PROP_CREATED, false);
return null;
}
});
}
/**
* This method asserts that the given List<BlogPostInfo> has NodeRefs in order of the specified date property.
*
* @param blogPosts
* @param property a Date property
* @param ascendingOrder <tt>true</tt> if ascending order, <tt>false</tt> for descending.
*/
private void assertNodeRefsAreSortedBy(List<BlogPostInfo> blogPosts, QName property, boolean ascendingOrder)
{
final PropertyDefinition propertyDef = DICTIONARY_SERVICE.getProperty(property);
assertNotNull("Property not recognised.", propertyDef);
assertEquals("Property was not a Date", DataTypeDefinition.DATETIME, propertyDef.getDataType().getName());
if (blogPosts.size() > 1)
{
for (int i = 0; i < blogPosts.size() - 1; i++)
{
NodeRef nodeRef1 = blogPosts.get(i).getNodeRef();
NodeRef nodeRef2 = blogPosts.get(i + 1).getNodeRef();
Date date1 = (Date) NODE_SERVICE.getProperty(nodeRef1, property);
Date date2 = (Date) NODE_SERVICE.getProperty(nodeRef2, property);
if (ascendingOrder)
{
assertTrue("BlogPosts not asc-sorted by " + property + ". Error at index " + i, date1.before(date2));
}
else
{
assertTrue("BlogPosts not desc-sorted by " + property + ". Error at index " + i, date1.after(date2));
}
}
}
}
@Test public void createTaggedDraftBlogPost() throws Exception
{
final List<String> tags = Arrays.asList(new String[]{"foo", "bar"});
final NodeRef blogPost = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
@Override
public NodeRef execute() throws Throwable
{
ChildAssociationRef newBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "draftWithTag", "Hello world", true);
TAGGING_SERVICE.addTags(newBlogPost.getChildRef(), tags);
testNodesToTidy.add(newBlogPost.getChildRef());
return newBlogPost.getChildRef();
}
});
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
PagingRequest pagingReq = new PagingRequest(0, 10, null);
PagingResults<BlogPostInfo> pagedResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq);
assertEquals("Expected one blog post", 1, pagedResults.getPage().size());
NodeRef blogNode = pagedResults.getPage().get(0).getNodeRef();
assertEquals("Incorrect NodeRef.", blogNode, blogPost);
List<String> recoveredTags = TAGGING_SERVICE.getTags(blogNode);
assertEquals("Incorrect tags.", tags, recoveredTags);
return null;
}
});
}
/**
* This test uses two different users to create draft and internally published blog posts.
* Then it ensures that each user sees the correct posts when they retrieve them from the service.
*/
@Test public void multipleUsersCreateDraftsAndPublishedPostsAndBrowse() throws Exception
{
// Admin creates a draft and an internally-published blog post.
final Pair<NodeRef, NodeRef> adminPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Pair<NodeRef, NodeRef>>()
{
@Override
public Pair<NodeRef, NodeRef> execute() throws Throwable
{
ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminDraft", "", true);
testNodesToTidy.add(newDraftBlogPost.getChildRef());
ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "adminPublished", "", false);
testNodesToTidy.add(newPublishedBlogPost.getChildRef());
return new Pair<NodeRef, NodeRef>(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef());
}
});
// Then another user does the same.
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER);
final Pair<NodeRef, NodeRef> userPosts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Pair<NodeRef, NodeRef>>()
{
@Override
public Pair<NodeRef, NodeRef> execute() throws Throwable
{
ChildAssociationRef newDraftBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userDraft", "", true);
testNodesToTidy.add(newDraftBlogPost.getChildRef());
ChildAssociationRef newPublishedBlogPost = BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "userPublished", "", false);
testNodesToTidy.add(newPublishedBlogPost.getChildRef());
return new Pair<NodeRef, NodeRef>(newDraftBlogPost.getChildRef(), newPublishedBlogPost.getChildRef());
}
});
// Now check what we see from the service.
AuthenticationUtil.setFullyAuthenticatedUser(ADMIN_USER);
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
PagingRequest pagingReq = new PagingRequest(0, 10, null);
PagingResults<BlogPostInfo> pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, ADMIN_USER, pagingReq);
assertEquals("Wrong number of admin draft blog posts", 1, pagedDraftResults.getPage().size());
NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef();
assertEquals("Incorrect admin draft NodeRef.", blogNode, adminPosts.getFirst());
PagingResults<BlogPostInfo> pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, ADMIN_USER, pagingReq);
assertEquals("Wrong number of admin published blog posts", 1, pagedPublishedResults.getPage().size());
blogNode = pagedPublishedResults.getPage().get(0).getNodeRef();
assertEquals("Incorrect admin published NodeRef.", blogNode, adminPosts.getSecond());
return null;
}
});
AuthenticationUtil.setFullyAuthenticatedUser(TEST_USER);
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
PagingRequest pagingReq = new PagingRequest(0, 10, null);
PagingResults<BlogPostInfo> pagedDraftResults = BLOG_SERVICE.getDrafts(BLOG_CONTAINER_NODE, TEST_USER, pagingReq);
assertEquals("Wrong number of user draft blog posts", 1, pagedDraftResults.getPage().size());
NodeRef blogNode = pagedDraftResults.getPage().get(0).getNodeRef();
assertEquals("Incorrect user draft NodeRef.", blogNode, userPosts.getFirst());
PagingResults<BlogPostInfo> pagedPublishedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, null, null, TEST_USER, pagingReq);
assertEquals("Wrong number of user published blog posts", 1, pagedPublishedResults.getPage().size());
blogNode = pagedPublishedResults.getPage().get(0).getNodeRef();
assertEquals("Incorrect user published NodeRef.", blogNode, userPosts.getSecond());
return null;
}
});
}
@Test public void getBlogPostsFilteredByDateRange() throws Exception
{
final int numberOfPosts = 31 + 31 + 29;
final List<NodeRef> posts = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<List<NodeRef>>()
{
@Override
public List<NodeRef> execute() throws Throwable
{
List<NodeRef> results = new ArrayList<NodeRef>();
for (int i = 0; i < numberOfPosts; i++)
{
ChildAssociationRef newBlogPost =
BLOG_SERVICE.createBlogPost(BLOG_CONTAINER_NODE, "date-specific-post" + i, "", false);
testNodesToTidy.add(newBlogPost.getChildRef());
results.add(newBlogPost.getChildRef());
}
return results;
}
});
// Now go through and set their creation dates to specific points in the past.
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
// FROM 1st December 1999
final Calendar current = Calendar.getInstance();
current.set(1999, 11, 1, 11, 0);
// should give us:
// 31 posts in december 99
// 31 posts in january 00
// 29 posts in february 00
Date currentDate = current.getTime();
for (NodeRef nr : posts)
{
// We'll permanently turn off auditing on this node.
// This should allow us to set the cm:created date without auditing overwriting our value.
// These nodes get deleted after the test anyway.
BEHAVIOUR_FILTER.disableBehaviour(nr, ContentModel.ASPECT_AUDITABLE);
// Yes, cm:published will be before cm:created. But I don't think that matter.
NODE_SERVICE.setProperty(nr, ContentModel.PROP_PUBLISHED, currentDate);
current.add(Calendar.DATE, 1);
currentDate = current.getTime();
}
return null;
}
});
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
PagingRequest pagingReq = new PagingRequest(0, 100, null);
Calendar cal = Calendar.getInstance();
cal.set(1999, 11, 1, 0, 0, 0);
Date firstDec99 = cal.getTime();
cal.set(2000, 0, 1, 0, 0, 0);
Date firstJan00 = cal.getTime();
cal.set(2000, 1, 1, 0, 0, 0);
Date firstFeb00 = cal.getTime();
cal.set(2000, 2, 1, 0, 0, 0);
Date firstMar00 = cal.getTime();
PagingResults<BlogPostInfo> pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstDec99, firstJan00, null, pagingReq);
assertEquals("Wrong number of user blog posts", 31, pagedResults.getPage().size());
pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstFeb00, firstMar00, null, pagingReq);
assertEquals("Wrong number of user blog posts", 29, pagedResults.getPage().size());
pagedResults = BLOG_SERVICE.getPublished(BLOG_CONTAINER_NODE, firstJan00, firstMar00, null, pagingReq);
assertEquals("Wrong number of user blog posts", 31 + 29, pagedResults.getPage().size());
return null;
}
});
}
private static void createUser(final String userName)
{
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (!AUTHENTICATION_SERVICE.authenticationExists(userName))
{
AUTHENTICATION_SERVICE.createAuthentication(userName, "PWD".toCharArray());
}
if (!PERSON_SERVICE.personExists(userName))
{
PropertyMap ppOne = new PropertyMap();
ppOne.put(ContentModel.PROP_USERNAME, userName);
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
PERSON_SERVICE.createPerson(ppOne);
}
return null;
}
});
}
private static void deleteUser(final String userName)
{
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (PERSON_SERVICE.personExists(userName))
{
PERSON_SERVICE.deletePerson(userName);
}
return null;
}
});
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.util.Date;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Parameters for {@link DraftsAndPublishedBlogPostsCannedQuery}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class DraftAndPublishedBlogPostsCannedQueryParams
{
private final NodeRef blogContainerNode;
private final String cmCreator;
private final Date createdFromDate;
private final Date createdToDate;
private final String tag;
public DraftAndPublishedBlogPostsCannedQueryParams(NodeRef blogContainerNodeRef,
String cmCreator,
Date createdFromDate,
Date createdToDate,
String tag)
{
this.blogContainerNode = blogContainerNodeRef;
this.cmCreator = cmCreator;
this.createdFromDate = createdFromDate;
this.createdToDate = createdToDate;
this.tag = tag;
}
public NodeRef getBlogContainerNode()
{
return blogContainerNode;
}
public String getCmCreator()
{
return cmCreator;
}
public Date getCreatedFromDate()
{
return createdFromDate;
}
public Date getCreatedToDate()
{
return createdToDate;
}
public String getTag()
{
return tag;
}
}

View File

@@ -0,0 +1,173 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
* This is a {@link CannedQuery} for the rather particular 'get my drafts and all published' blog-post query.
*
* @author Neil Mc Erlean
* @since 4.0
*
* @see BlogService#getMyDraftsAndAllPublished(NodeRef, Date, Date, String, org.alfresco.query.PagingRequest)
*/
public class DraftsAndPublishedBlogPostsCannedQuery extends AbstractCannedQueryPermissions<BlogPostInfo>
{
private final NodeService rawNodeService;
private final TaggingService taggingService;
public DraftsAndPublishedBlogPostsCannedQuery(
NodeService rawNodeService,
TaggingService taggingService,
MethodSecurityInterceptor methodSecurityInterceptor,
Method method,
CannedQueryParameters params,
String queryExecutionId)
{
super(params, queryExecutionId, methodSecurityInterceptor, method);
this.rawNodeService = rawNodeService;
this.taggingService = taggingService;
}
@Override
protected List<BlogPostInfo> queryAndFilter(CannedQueryParameters parameters)
{
Object paramBeanObj = parameters.getParameterBean();
if (paramBeanObj == null)
throw new NullPointerException("Null GetBlogPosts query params");
DraftAndPublishedBlogPostsCannedQueryParams paramBean = (DraftAndPublishedBlogPostsCannedQueryParams) paramBeanObj;
String requestedTag = paramBean.getTag();
Date createdFromDate = paramBean.getCreatedFromDate();
Date createdToDate = paramBean.getCreatedToDate();
List<ChildAssociationRef> childAssocs = getAllBlogNodes(paramBean.getBlogContainerNode());
List<BlogPostInfo> filteredNodeRefs = new ArrayList<BlogPostInfo>();
for (ChildAssociationRef chAssRef : childAssocs)
{
NodeRef nextBlogNode = chAssRef.getChildRef();
// Is this next node in the list to be included in the results?
boolean nextNodeIsAcceptable = true;
// Return all published Blog Posts
if (rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED) != null)
{
// Intentionally empty
}
else
{
// We're relying on cm:published being null below i.e. we are dealing with draft blog posts.
if (!rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATOR).equals(paramBean.getCmCreator()))
{
nextNodeIsAcceptable = false;
}
}
// Only return blogs created within the specified dates
Date actualCreatedDate = (Date) rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATED);
if (actualCreatedDate != null)
{
if (createdFromDate != null && actualCreatedDate.before(createdFromDate))
{
nextNodeIsAcceptable = false;
}
if (createdToDate != null && actualCreatedDate.after(createdToDate))
{
nextNodeIsAcceptable = false;
}
}
// Only return blog posts tagged with the specified tag string.
if (requestedTag != null && !taggingService.getTags(nextBlogNode).contains(requestedTag))
{
nextNodeIsAcceptable = false;
}
if (nextNodeIsAcceptable)
{
filteredNodeRefs.add(new BlogPostInfoImpl(nextBlogNode, rawNodeService.getProperties(nextBlogNode)));
}
}
List<Pair<? extends Object, SortOrder>> sortPairs = parameters.getSortDetails().getSortPairs();
// For now, the BlogService only sorts by a single property.
if (sortPairs != null && !sortPairs.isEmpty())
{
Pair<? extends Object, SortOrder> sortPair = sortPairs.get(0);
QName sortProperty = (QName) sortPair.getFirst();
final PropertyBasedComparator createdDateComparator = new PropertyBasedComparator(sortProperty, rawNodeService);
if (sortPair.getSecond() == SortOrder.DESCENDING)
{
Collections.sort(filteredNodeRefs, Collections.reverseOrder(createdDateComparator));
}
}
return filteredNodeRefs;
}
private List<ChildAssociationRef> getAllBlogNodes(NodeRef containerNode)
{
final Set<QName> childNodeTypes = new HashSet<QName>();
childNodeTypes.add(ContentModel.TYPE_CONTENT);
// This will, of course, retrieve all the blog posts which may be a very long list.
List<ChildAssociationRef> childAssocs = rawNodeService.getChildAssocs(containerNode, childNodeTypes);
return childAssocs;
}
@Override
protected boolean isApplyPostQuerySorting()
{
// No post-query sorting. It's done within the queryAndFilter() method above.
return false;
}
@Override
protected boolean isApplyPostQueryPermissions()
{
return true;
}
}

View File

@@ -0,0 +1,174 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.query.AbstractCannedQueryFactory;
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.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyCheck;
/**
* A {@link CannedQueryFactory} for the creation of {@link DraftsAndPublishedBlogPostsCannedQuery}s.
*
* Currently, this is implemented using calls to lower-level services, notably the {@link NodeService} rather
* than database queries. This may change in the future.
*
* @since 4.0
* @author Neil Mc Erlean.
*/
public class DraftsAndPublishedBlogPostsCannedQueryFactory extends AbstractCannedQueryFactory<BlogPostInfo>
{
private MethodSecurityInterceptor methodSecurityInterceptor;
private String methodName;
private Object methodService;
private NodeService rawNodeService;
private TaggingService taggingService;
public void setRawNodeService(NodeService nodeService)
{
this.rawNodeService = nodeService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
public void setMethodSecurityInterceptor(MethodSecurityInterceptor methodSecurityInterceptor)
{
this.methodSecurityInterceptor = methodSecurityInterceptor;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public void setMethodService(Object methodService)
{
this.methodService = methodService;
}
@Override
public CannedQuery<BlogPostInfo> getCannedQuery(CannedQueryParameters parameters)
{
Method method = null;
for (Method m : methodService.getClass().getMethods())
{
// note: currently matches first found
if (m.getName().equals(methodName))
{
method = m;
break;
}
}
if (method == null)
{
throw new AlfrescoRuntimeException("Method not found: "+methodName);
}
// if not passed in (TODO or not in future cache) then generate a new query execution id
String queryExecutionId = (parameters.getQueryExecutionId() == null ? super.getQueryExecutionId(parameters) : parameters.getQueryExecutionId());
final DraftsAndPublishedBlogPostsCannedQuery cq = new DraftsAndPublishedBlogPostsCannedQuery(rawNodeService, taggingService,
methodSecurityInterceptor, method, parameters, queryExecutionId);
return (CannedQuery<BlogPostInfo>) cq;
}
public CannedQuery<BlogPostInfo> getCannedQuery(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, String tag, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
//FIXME Need tenant service like for GetChildren?
DraftAndPublishedBlogPostsCannedQueryParams paramBean = new DraftAndPublishedBlogPostsCannedQueryParams(blogContainerNode,
byUser,
fromDate, toDate, tag);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_PUBLISHED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
private CannedQuerySortDetails createCQSortDetails(QName sortProp, SortOrder sortOrder)
{
CannedQuerySortDetails cqsd = null;
List<Pair<? extends Object, SortOrder>> sortPairs = new ArrayList<Pair<? extends Object, SortOrder>>();
sortPairs.add(new Pair<QName, SortOrder>(sortProp, sortOrder));
cqsd = new CannedQuerySortDetails(sortPairs);
return cqsd;
}
private CannedQueryPageDetails createCQPageDetails(PagingRequest pagingReq)
{
int skipCount = pagingReq.getSkipCount();
if (skipCount == -1)
{
skipCount = CannedQueryPageDetails.DEFAULT_SKIP_RESULTS;
}
int maxItems = pagingReq.getMaxItems();
if (maxItems == -1)
{
maxItems = CannedQueryPageDetails.DEFAULT_PAGE_SIZE;
}
// page details
CannedQueryPageDetails cqpd = new CannedQueryPageDetails(skipCount, maxItems, CannedQueryPageDetails.DEFAULT_PAGE_NUMBER, CannedQueryPageDetails.DEFAULT_PAGE_COUNT);
return cqpd;
}
@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "methodSecurityInterceptor", methodSecurityInterceptor);
PropertyCheck.mandatory(this, "methodService", methodService);
PropertyCheck.mandatory(this, "methodName", methodName);
}
}

View File

@@ -0,0 +1,183 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
* This class provides support for several {@link CannedQuery canned queries} used by the
* {@link BlogService}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class GetBlogPostsCannedQuery extends AbstractCannedQueryPermissions<BlogPostInfo>
{
/*
* This must be the small n nodeService, not the big N NodeService. See below.
*/
private final NodeService rawNodeService;
public GetBlogPostsCannedQuery(
NodeService rawNodeService,
MethodSecurityInterceptor methodSecurityInterceptor,
Method method,
CannedQueryParameters params,
String queryExecutionId)
{
super(params, queryExecutionId, methodSecurityInterceptor, method);
this.rawNodeService = rawNodeService;
}
@Override
protected List<BlogPostInfo> queryAndFilter(CannedQueryParameters parameters)
{
Object paramBeanObj = parameters.getParameterBean();
if (paramBeanObj == null)
throw new NullPointerException("Null GetBlogPosts query params");
GetBlogPostsCannedQueryParams paramBean = (GetBlogPostsCannedQueryParams) paramBeanObj;
String requestedCreator = paramBean.getCmCreator();
boolean isPublished = paramBean.getIsPublished();
Date publishedFromDate = paramBean.getPublishedFromDate();
Date publishedToDate = paramBean.getPublishedToDate();
List<QName> requiredAspects = paramBean.getRequiredAspects();
// Retrieve all blog-post nodes under the blogContainer root. This could potentially
// be a long list of NodeRefs and it is possible that future optimisation towards DB queries
// would avoid the retrieval of potentially long lists like this.
// It is however important to retrieve the full list of relevant nodes before any sorting
// is applied. Otherwise it would be possible to have nodes that were not retrieved, which after sorting
// could be at the front of this list.
// For that reason, we must use the small n nodeService, and not the large N NodeService, because the
// latter truncates results.
List<ChildAssociationRef> childAssocs = getAllBlogNodes(paramBean.getBlogContainerNode());
List<BlogPostInfo> filteredNodeRefs = new ArrayList<BlogPostInfo>();
for (ChildAssociationRef chAssRef : childAssocs)
{
// Is the nextBlogPostNode going to be included or not?
boolean nextNodeIsAcceptable = true;
NodeRef nextBlogNode = chAssRef.getChildRef();
// Only return blog-posts whose cm:published status matches that requested.
final boolean nextBlogNodeIsPublished = rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED) != null;
if (nextBlogNodeIsPublished != isPublished)
{
nextNodeIsAcceptable = false;
}
// Only return blog posts whose creator matches the given username, if there is one.
if (requestedCreator != null && !rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATOR).equals(requestedCreator))
{
nextNodeIsAcceptable = false;
}
// Only return blogs published within the specified dates
Date actualPublishedDate = (Date) rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED);
if (actualPublishedDate != null)
{
if (publishedFromDate != null && actualPublishedDate.before(publishedFromDate))
{
nextNodeIsAcceptable = false;
}
if (publishedToDate != null && actualPublishedDate.after(publishedToDate))
{
nextNodeIsAcceptable = false;
}
}
// Only those with the required aspects.
for (QName aspect : requiredAspects)
{
if (!rawNodeService.hasAspect(nextBlogNode, aspect))
{
nextNodeIsAcceptable = false;
}
}
// If all the above conditions are true...
if (nextNodeIsAcceptable)
{
filteredNodeRefs.add(new BlogPostInfoImpl(nextBlogNode, rawNodeService.getProperties(nextBlogNode)));
}
}
List<Pair<? extends Object, SortOrder>> sortPairs = parameters.getSortDetails().getSortPairs();
// For now, the BlogService only sorts by a single property.
if (sortPairs != null && !sortPairs.isEmpty())
{
Pair<? extends Object, SortOrder> sortPair = sortPairs.get(0);
QName sortProperty = (QName) sortPair.getFirst();
final PropertyBasedComparator createdDateComparator = new PropertyBasedComparator(sortProperty, rawNodeService);
if (sortPair.getSecond() == SortOrder.DESCENDING)
{
Collections.sort(filteredNodeRefs, Collections.reverseOrder(createdDateComparator));
}
}
return filteredNodeRefs;
}
private List<ChildAssociationRef> getAllBlogNodes(NodeRef containerNode)
{
final Set<QName> childNodeTypes = new HashSet<QName>();
childNodeTypes.add(ContentModel.TYPE_CONTENT);
// This will, of course, retrieve all the blog posts which may be a very long list.
List<ChildAssociationRef> childAssocs = rawNodeService.getChildAssocs(containerNode, childNodeTypes);
return childAssocs;
}
@Override
protected boolean isApplyPostQuerySorting()
{
// No post-query sorting. It's done within the queryAndFilter() method above.
return false;
}
@Override
protected boolean isApplyPostQueryPermissions()
{
return true;
}
}

View File

@@ -0,0 +1,223 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.BlogIntegrationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.query.AbstractCannedQueryFactory;
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.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyCheck;
/**
* A {@link CannedQueryFactory} for various queries relating to {@link BlogPostInfo blog-posts}.
* Currently, this is implemented using calls to lower-level services, notably the {@link NodeService} rather
* than database queries. This may change in the future.
*
* @author Neil Mc Erlean.
* @since 4.0
*
* @see BlogService#getDrafts(NodeRef, String, PagingRequest)
* @see BlogService#getPublished(NodeRef, Date, Date, String, PagingRequest)
*/
public class GetBlogPostsCannedQueryFactory extends AbstractCannedQueryFactory<BlogPostInfo>
{
private MethodSecurityInterceptor methodSecurityInterceptor;
private String methodName;
private Object methodService;
private NodeService rawNodeService;
public void setRawNodeService(NodeService nodeService)
{
this.rawNodeService = nodeService;
}
public void setMethodSecurityInterceptor(MethodSecurityInterceptor methodSecurityInterceptor)
{
this.methodSecurityInterceptor = methodSecurityInterceptor;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public void setMethodService(Object methodService)
{
this.methodService = methodService;
}
@Override
public CannedQuery<BlogPostInfo> getCannedQuery(CannedQueryParameters parameters)
{
Method method = null;
for (Method m : methodService.getClass().getMethods())
{
// note: currently matches first found
if (m.getName().equals(methodName))
{
method = m;
break;
}
}
if (method == null)
{
throw new AlfrescoRuntimeException("Method not found: "+methodName);
}
String queryExecutionId = (parameters.getQueryExecutionId() == null ? super.getQueryExecutionId(parameters) : parameters.getQueryExecutionId());
final GetBlogPostsCannedQuery cq = new GetBlogPostsCannedQuery(rawNodeService, methodSecurityInterceptor, method, parameters, queryExecutionId);
return (CannedQuery<BlogPostInfo>) cq;
}
public CannedQuery<BlogPostInfo> getGetDraftsCannedQuery(NodeRef blogContainerNode, String username, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
//FIXME Need tenant service like for GetChildren?
boolean isPublished = false;
List<QName> requiredAspects = null;
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
username,
isPublished,
null, null,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_CREATED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
public CannedQuery<BlogPostInfo> getGetPublishedExternallyCannedQuery(NodeRef blogContainerNode, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
boolean isPublished = true;
List<QName> requiredAspects = Arrays.asList(new QName[]{BlogIntegrationModel.ASPECT_BLOG_POST});
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
null,
isPublished,
null, null,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(BlogIntegrationModel.PROP_POSTED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
public CannedQuery<BlogPostInfo> getGetPublishedCannedQuery(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
boolean isPublished = true;
List<QName> requiredAspects = null;
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
byUser,
isPublished,
fromDate, toDate,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_PUBLISHED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
private CannedQuerySortDetails createCQSortDetails(QName sortProp, SortOrder sortOrder)
{
CannedQuerySortDetails cqsd = null;
List<Pair<? extends Object, SortOrder>> sortPairs = new ArrayList<Pair<? extends Object, SortOrder>>();
sortPairs.add(new Pair<QName, SortOrder>(sortProp, sortOrder));
cqsd = new CannedQuerySortDetails(sortPairs);
return cqsd;
}
private CannedQueryPageDetails createCQPageDetails(PagingRequest pagingReq)
{
int skipCount = pagingReq.getSkipCount();
if (skipCount == -1)
{
skipCount = CannedQueryPageDetails.DEFAULT_SKIP_RESULTS;
}
int maxItems = pagingReq.getMaxItems();
if (maxItems == -1)
{
maxItems = CannedQueryPageDetails.DEFAULT_PAGE_SIZE;
}
// page details
CannedQueryPageDetails cqpd = new CannedQueryPageDetails(skipCount, maxItems, CannedQueryPageDetails.DEFAULT_PAGE_NUMBER, CannedQueryPageDetails.DEFAULT_PAGE_COUNT);
return cqpd;
}
@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "methodSecurityInterceptor", methodSecurityInterceptor);
PropertyCheck.mandatory(this, "methodService", methodService);
PropertyCheck.mandatory(this, "methodName", methodName);
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Parameter objects for {@link GetBlogPostsCannedQuery}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class GetBlogPostsCannedQueryParams
{
private final NodeRef blogContainerNode;
private final String cmCreator;
/**
* <tt>true</tt> means the blog-posts should be cm:published, <tt>false</tt> means they should not.
*/
private final boolean isPublished;
private final Date publishedFromDate;
private final Date publishedToDate;
private final List<QName> requiredAspects;
public GetBlogPostsCannedQueryParams(NodeRef blogContainerNodeRef,
String cmCreator,
boolean isPublished,
Date publishedFromDate,
Date publishedToDate,
List<QName> requiredAspects)
{
this.blogContainerNode = blogContainerNodeRef;
this.cmCreator = cmCreator;
this.isPublished = isPublished;
this.publishedFromDate = publishedFromDate;
this.publishedToDate = publishedToDate;
if (requiredAspects == null)
{
requiredAspects = Collections.emptyList();
}
this.requiredAspects = requiredAspects;
}
public NodeRef getBlogContainerNode()
{
return blogContainerNode;
}
public String getCmCreator()
{
return cmCreator;
}
public boolean getIsPublished()
{
return this.isPublished;
}
public Date getPublishedFromDate()
{
return publishedFromDate;
}
public Date getPublishedToDate()
{
return publishedToDate;
}
public List<QName> getRequiredAspects()
{
return Collections.unmodifiableList(this.requiredAspects);
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import org.alfresco.query.PagingResults;
/**
* @since 4.0
*/
public interface PagingBlogPostInfoResults extends PagingResults<BlogPostInfo>
{
}

View File

@@ -0,0 +1,80 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.util.List;
import org.alfresco.query.PermissionedResults;
import org.alfresco.util.Pair;
/**
* A simple results holder object for data relating to {@link BlogPostInfo blog-posts}, as
* returned by the {@link BlogService}
*
* @since 4.0
* @author Neil Mc Erlean.
*/
class PagingBlogPostInfoResultsImpl implements PagingBlogPostInfoResults, PermissionedResults
{
private List<BlogPostInfo> blogPosts;
private boolean hasMoreItems;
private Pair<Integer, Integer> totalResultCount;
private String queryExecutionId;
private boolean permissionsApplied;
public PagingBlogPostInfoResultsImpl(List<BlogPostInfo> nodeInfos, boolean hasMoreItems, Pair<Integer, Integer> totalResultCount, String queryExecutionId, boolean permissionsApplied)
{
this.blogPosts = nodeInfos;
this.hasMoreItems = hasMoreItems;
this.totalResultCount = totalResultCount;
this.queryExecutionId = queryExecutionId;
this.permissionsApplied = permissionsApplied;
}
@Override
public List<BlogPostInfo> getPage()
{
return blogPosts;
}
@Override
public boolean hasMoreItems()
{
return hasMoreItems;
}
@Override
public Pair<Integer, Integer> getTotalResultCount()
{
return totalResultCount;
}
@Override
public String getQueryExecutionId()
{
return queryExecutionId;
}
@Override
public boolean permissionsApplied()
{
return permissionsApplied;
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog;
import java.util.Comparator;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Utility class to sort {@link BlogPostInfo}s on the basis of a Comparable property.
* Comparisons of two null properties are considered 'equal' by this comparator.
* Comparisons involving one null and one non-null property will return the null property as
* being 'before' the non-null property.
*
* Note that it is the responsibility of the calling code to ensure that the specified
* property values actually implement Comparable themselves.
*/
class PropertyBasedComparator implements Comparator<BlogPostInfo>
{
private QName comparableProperty;
private NodeService nodeService;
public PropertyBasedComparator(QName comparableProperty, NodeService nodeService)
{
this.comparableProperty = comparableProperty;
this.nodeService = nodeService;
}
@SuppressWarnings("unchecked")
@Override
public int compare(BlogPostInfo nr1, BlogPostInfo nr2)
{
Comparable prop1 = (Comparable) nodeService.getProperty(nr1.getNodeRef(), comparableProperty);
Comparable prop2 = (Comparable) nodeService.getProperty(nr2.getNodeRef(), comparableProperty);
if (prop1 == null && prop2 == null)
{
return 0;
}
else if (prop1 == null && prop2 != null)
{
return -1;
}
else if (prop1 != null && prop2 == null)
{
return 1;
}
else
{
return prop1.compareTo(prop2);
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* A simple data object responsible for holding information relevant to blog post NodeRefs.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class BlogPostInfoImpl implements BlogPostInfo
{
private NodeRef nodeRef;
private Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
BlogPostInfoImpl(NodeRef nodeRef, Map<QName, Serializable> properties)
{
this.nodeRef = nodeRef;
this.properties = properties;
}
/**
* @see #getNodeRef()
* @see NodeRef#equals(Object)
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
else if (this == obj)
{
return true;
}
else if (obj instanceof BlogPostInfoImpl == false)
{
return false;
}
BlogPostInfoImpl that = (BlogPostInfoImpl) obj;
return (this.getNodeRef().equals(that.getNodeRef()));
}
/**
* @see #getNodeRef()
* @see NodeRef#hashCode()
*/
@Override
public int hashCode()
{
return getNodeRef().hashCode();
}
@Override
public String toString()
{
StringBuilder sb = new StringBuilder(80);
sb.append(BlogPostInfo.class.getSimpleName())
.append("[name=").append(getName())
.append(", nodeRef=").append(nodeRef);
sb.append("]");
return sb.toString();
}
@Override
public NodeRef getNodeRef()
{
return nodeRef;
}
@Override
public String getName()
{
return (String) properties.get(ContentModel.PROP_NAME);
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.blog.BlogService;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
* This is a {@link CannedQuery} for the rather particular 'get my drafts and all published' blog-post query.
*
* @author Neil Mc Erlean
* @since 4.0
*
* @see BlogService#getMyDraftsAndAllPublished(NodeRef, Date, Date, String, org.alfresco.query.PagingRequest)
*/
public class DraftsAndPublishedBlogPostsCannedQuery extends AbstractCannedQueryPermissions<BlogPostInfo>
{
private final NodeService rawNodeService;
private final TaggingService taggingService;
public DraftsAndPublishedBlogPostsCannedQuery(
NodeService rawNodeService,
TaggingService taggingService,
MethodSecurityInterceptor methodSecurityInterceptor,
Method method,
CannedQueryParameters params,
String queryExecutionId)
{
super(params, queryExecutionId, methodSecurityInterceptor, method);
this.rawNodeService = rawNodeService;
this.taggingService = taggingService;
}
@Override
protected List<BlogPostInfo> queryAndFilter(CannedQueryParameters parameters)
{
Object paramBeanObj = parameters.getParameterBean();
if (paramBeanObj == null)
throw new NullPointerException("Null GetBlogPosts query params");
DraftsAndPublishedBlogPostsCannedQueryParams paramBean = (DraftsAndPublishedBlogPostsCannedQueryParams) paramBeanObj;
String requestedTag = paramBean.getTag();
Date createdFromDate = paramBean.getCreatedFromDate();
Date createdToDate = paramBean.getCreatedToDate();
List<ChildAssociationRef> childAssocs = getAllBlogNodes(paramBean.getBlogContainerNode());
List<BlogPostInfo> filteredNodeRefs = new ArrayList<BlogPostInfo>();
for (ChildAssociationRef chAssRef : childAssocs)
{
NodeRef nextBlogNode = chAssRef.getChildRef();
// Is this next node in the list to be included in the results?
boolean nextNodeIsAcceptable = true;
// Return all published Blog Posts
if (rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED) != null)
{
// Intentionally empty
}
else
{
// We're relying on cm:published being null below i.e. we are dealing with draft blog posts.
if (!rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATOR).equals(paramBean.getCmCreator()))
{
nextNodeIsAcceptable = false;
}
}
// Only return blogs created within the specified dates
Date actualCreatedDate = (Date) rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATED);
if (actualCreatedDate != null)
{
if (createdFromDate != null && actualCreatedDate.before(createdFromDate))
{
nextNodeIsAcceptable = false;
}
if (createdToDate != null && actualCreatedDate.after(createdToDate))
{
nextNodeIsAcceptable = false;
}
}
// Only return blog posts tagged with the specified tag string.
if (requestedTag != null && !taggingService.getTags(nextBlogNode).contains(requestedTag))
{
nextNodeIsAcceptable = false;
}
if (nextNodeIsAcceptable)
{
filteredNodeRefs.add(new BlogPostInfoImpl(nextBlogNode, rawNodeService.getProperties(nextBlogNode)));
}
}
List<Pair<? extends Object, SortOrder>> sortPairs = parameters.getSortDetails().getSortPairs();
// For now, the BlogService only sorts by a single property.
if (sortPairs != null && !sortPairs.isEmpty())
{
Pair<? extends Object, SortOrder> sortPair = sortPairs.get(0);
QName sortProperty = (QName) sortPair.getFirst();
final PropertyBasedComparator createdDateComparator = new PropertyBasedComparator(sortProperty, rawNodeService);
if (sortPair.getSecond() == SortOrder.DESCENDING)
{
Collections.sort(filteredNodeRefs, Collections.reverseOrder(createdDateComparator));
}
}
return filteredNodeRefs;
}
private List<ChildAssociationRef> getAllBlogNodes(NodeRef containerNode)
{
final Set<QName> childNodeTypes = new HashSet<QName>();
childNodeTypes.add(ContentModel.TYPE_CONTENT);
// This will, of course, retrieve all the blog posts which may be a very long list.
List<ChildAssociationRef> childAssocs = rawNodeService.getChildAssocs(containerNode, childNodeTypes);
return childAssocs;
}
@Override
protected boolean isApplyPostQuerySorting()
{
// No post-query sorting. It's done within the queryAndFilter() method above.
return false;
}
@Override
protected boolean isApplyPostQueryPermissions()
{
return true;
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.query.AbstractCannedQueryFactory;
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.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyCheck;
/**
* A {@link CannedQueryFactory} for the creation of {@link DraftsAndPublishedBlogPostsCannedQuery}s.
*
* Currently, this is implemented using calls to lower-level services, notably the {@link NodeService} rather
* than database queries. This may change in the future.
*
* @since 4.0
* @author Neil Mc Erlean.
*/
public class DraftsAndPublishedBlogPostsCannedQueryFactory extends AbstractCannedQueryFactory<BlogPostInfo>
{
private MethodSecurityInterceptor methodSecurityInterceptor;
private String methodName;
private Object methodService;
private NodeService rawNodeService;
private TaggingService taggingService;
public void setRawNodeService(NodeService nodeService)
{
this.rawNodeService = nodeService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
public void setMethodSecurityInterceptor(MethodSecurityInterceptor methodSecurityInterceptor)
{
this.methodSecurityInterceptor = methodSecurityInterceptor;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public void setMethodService(Object methodService)
{
this.methodService = methodService;
}
@Override
public CannedQuery<BlogPostInfo> getCannedQuery(CannedQueryParameters parameters)
{
Method method = null;
for (Method m : methodService.getClass().getMethods())
{
// note: currently matches first found
if (m.getName().equals(methodName))
{
method = m;
break;
}
}
if (method == null)
{
throw new AlfrescoRuntimeException("Method not found: "+methodName);
}
// if not passed in (TODO or not in future cache) then generate a new query execution id
String queryExecutionId = (parameters.getQueryExecutionId() == null ? super.getQueryExecutionId(parameters) : parameters.getQueryExecutionId());
final DraftsAndPublishedBlogPostsCannedQuery cq = new DraftsAndPublishedBlogPostsCannedQuery(rawNodeService, taggingService,
methodSecurityInterceptor, method, parameters, queryExecutionId);
return (CannedQuery<BlogPostInfo>) cq;
}
public CannedQuery<BlogPostInfo> getCannedQuery(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, String tag, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
//FIXME Need tenant service like for GetChildren?
DraftsAndPublishedBlogPostsCannedQueryParams paramBean = new DraftsAndPublishedBlogPostsCannedQueryParams(blogContainerNode,
byUser,
fromDate, toDate, tag);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_PUBLISHED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
private CannedQuerySortDetails createCQSortDetails(QName sortProp, SortOrder sortOrder)
{
CannedQuerySortDetails cqsd = null;
List<Pair<? extends Object, SortOrder>> sortPairs = new ArrayList<Pair<? extends Object, SortOrder>>();
sortPairs.add(new Pair<QName, SortOrder>(sortProp, sortOrder));
cqsd = new CannedQuerySortDetails(sortPairs);
return cqsd;
}
private CannedQueryPageDetails createCQPageDetails(PagingRequest pagingReq)
{
int skipCount = pagingReq.getSkipCount();
if (skipCount == -1)
{
skipCount = CannedQueryPageDetails.DEFAULT_SKIP_RESULTS;
}
int maxItems = pagingReq.getMaxItems();
if (maxItems == -1)
{
maxItems = CannedQueryPageDetails.DEFAULT_PAGE_SIZE;
}
// page details
CannedQueryPageDetails cqpd = new CannedQueryPageDetails(skipCount, maxItems, CannedQueryPageDetails.DEFAULT_PAGE_NUMBER, CannedQueryPageDetails.DEFAULT_PAGE_COUNT);
return cqpd;
}
@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "methodSecurityInterceptor", methodSecurityInterceptor);
PropertyCheck.mandatory(this, "methodService", methodService);
PropertyCheck.mandatory(this, "methodName", methodName);
}
}

View File

@@ -0,0 +1,76 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.util.Date;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Parameters for {@link DraftsAndPublishedBlogPostsCannedQuery}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class DraftsAndPublishedBlogPostsCannedQueryParams
{
private final NodeRef blogContainerNode;
private final String cmCreator;
private final Date createdFromDate;
private final Date createdToDate;
private final String tag;
public DraftsAndPublishedBlogPostsCannedQueryParams(NodeRef blogContainerNodeRef,
String cmCreator,
Date createdFromDate,
Date createdToDate,
String tag)
{
this.blogContainerNode = blogContainerNodeRef;
this.cmCreator = cmCreator;
this.createdFromDate = createdFromDate;
this.createdToDate = createdToDate;
this.tag = tag;
}
public NodeRef getBlogContainerNode()
{
return blogContainerNode;
}
public String getCmCreator()
{
return cmCreator;
}
public Date getCreatedFromDate()
{
return createdFromDate;
}
public Date getCreatedToDate()
{
return createdToDate;
}
public String getTag()
{
return tag;
}
}

View File

@@ -0,0 +1,185 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.query.CannedQuery;
import org.alfresco.query.CannedQueryParameters;
import org.alfresco.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.blog.BlogService;
import org.alfresco.repo.security.permissions.impl.acegi.AbstractCannedQueryPermissions;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
* This class provides support for several {@link CannedQuery canned queries} used by the
* {@link BlogService}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class GetBlogPostsCannedQuery extends AbstractCannedQueryPermissions<BlogPostInfo>
{
/*
* This must be the small n nodeService, not the big N NodeService. See below.
*/
private final NodeService rawNodeService;
public GetBlogPostsCannedQuery(
NodeService rawNodeService,
MethodSecurityInterceptor methodSecurityInterceptor,
Method method,
CannedQueryParameters params,
String queryExecutionId)
{
super(params, queryExecutionId, methodSecurityInterceptor, method);
this.rawNodeService = rawNodeService;
}
@Override
protected List<BlogPostInfo> queryAndFilter(CannedQueryParameters parameters)
{
Object paramBeanObj = parameters.getParameterBean();
if (paramBeanObj == null)
throw new NullPointerException("Null GetBlogPosts query params");
GetBlogPostsCannedQueryParams paramBean = (GetBlogPostsCannedQueryParams) paramBeanObj;
String requestedCreator = paramBean.getCmCreator();
boolean isPublished = paramBean.getIsPublished();
Date publishedFromDate = paramBean.getPublishedFromDate();
Date publishedToDate = paramBean.getPublishedToDate();
List<QName> requiredAspects = paramBean.getRequiredAspects();
// Retrieve all blog-post nodes under the blogContainer root. This could potentially
// be a long list of NodeRefs and it is possible that future optimisation towards DB queries
// would avoid the retrieval of potentially long lists like this.
// It is however important to retrieve the full list of relevant nodes before any sorting
// is applied. Otherwise it would be possible to have nodes that were not retrieved, which after sorting
// could be at the front of this list.
// For that reason, we must use the small n nodeService, and not the large N NodeService, because the
// latter truncates results.
List<ChildAssociationRef> childAssocs = getAllBlogNodes(paramBean.getBlogContainerNode());
List<BlogPostInfo> filteredNodeRefs = new ArrayList<BlogPostInfo>();
for (ChildAssociationRef chAssRef : childAssocs)
{
// Is the nextBlogPostNode going to be included or not?
boolean nextNodeIsAcceptable = true;
NodeRef nextBlogNode = chAssRef.getChildRef();
// Only return blog-posts whose cm:published status matches that requested.
final boolean nextBlogNodeIsPublished = rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED) != null;
if (nextBlogNodeIsPublished != isPublished)
{
nextNodeIsAcceptable = false;
}
// Only return blog posts whose creator matches the given username, if there is one.
if (requestedCreator != null && !rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_CREATOR).equals(requestedCreator))
{
nextNodeIsAcceptable = false;
}
// Only return blogs published within the specified dates
Date actualPublishedDate = (Date) rawNodeService.getProperty(nextBlogNode, ContentModel.PROP_PUBLISHED);
if (actualPublishedDate != null)
{
if (publishedFromDate != null && actualPublishedDate.before(publishedFromDate))
{
nextNodeIsAcceptable = false;
}
if (publishedToDate != null && actualPublishedDate.after(publishedToDate))
{
nextNodeIsAcceptable = false;
}
}
// Only those with the required aspects.
for (QName aspect : requiredAspects)
{
if (!rawNodeService.hasAspect(nextBlogNode, aspect))
{
nextNodeIsAcceptable = false;
}
}
// If all the above conditions are true...
if (nextNodeIsAcceptable)
{
filteredNodeRefs.add(new BlogPostInfoImpl(nextBlogNode, rawNodeService.getProperties(nextBlogNode)));
}
}
List<Pair<? extends Object, SortOrder>> sortPairs = parameters.getSortDetails().getSortPairs();
// For now, the BlogService only sorts by a single property.
if (sortPairs != null && !sortPairs.isEmpty())
{
Pair<? extends Object, SortOrder> sortPair = sortPairs.get(0);
QName sortProperty = (QName) sortPair.getFirst();
final PropertyBasedComparator createdDateComparator = new PropertyBasedComparator(sortProperty, rawNodeService);
if (sortPair.getSecond() == SortOrder.DESCENDING)
{
Collections.sort(filteredNodeRefs, Collections.reverseOrder(createdDateComparator));
}
}
return filteredNodeRefs;
}
private List<ChildAssociationRef> getAllBlogNodes(NodeRef containerNode)
{
final Set<QName> childNodeTypes = new HashSet<QName>();
childNodeTypes.add(ContentModel.TYPE_CONTENT);
// This will, of course, retrieve all the blog posts which may be a very long list.
List<ChildAssociationRef> childAssocs = rawNodeService.getChildAssocs(containerNode, childNodeTypes);
return childAssocs;
}
@Override
protected boolean isApplyPostQuerySorting()
{
// No post-query sorting. It's done within the queryAndFilter() method above.
return false;
}
@Override
protected boolean isApplyPostQueryPermissions()
{
return true;
}
}

View File

@@ -0,0 +1,225 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.BlogIntegrationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.query.AbstractCannedQueryFactory;
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.query.CannedQuerySortDetails.SortOrder;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.blog.BlogService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.impl.acegi.MethodSecurityInterceptor;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyCheck;
/**
* A {@link CannedQueryFactory} for various queries relating to {@link BlogPostInfo blog-posts}.
* Currently, this is implemented using calls to lower-level services, notably the {@link NodeService} rather
* than database queries. This may change in the future.
*
* @author Neil Mc Erlean.
* @since 4.0
*
* @see BlogService#getDrafts(NodeRef, String, PagingRequest)
* @see BlogService#getPublished(NodeRef, Date, Date, String, PagingRequest)
*/
public class GetBlogPostsCannedQueryFactory extends AbstractCannedQueryFactory<BlogPostInfo>
{
private MethodSecurityInterceptor methodSecurityInterceptor;
private String methodName;
private Object methodService;
private NodeService rawNodeService;
public void setRawNodeService(NodeService nodeService)
{
this.rawNodeService = nodeService;
}
public void setMethodSecurityInterceptor(MethodSecurityInterceptor methodSecurityInterceptor)
{
this.methodSecurityInterceptor = methodSecurityInterceptor;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public void setMethodService(Object methodService)
{
this.methodService = methodService;
}
@Override
public CannedQuery<BlogPostInfo> getCannedQuery(CannedQueryParameters parameters)
{
Method method = null;
for (Method m : methodService.getClass().getMethods())
{
// note: currently matches first found
if (m.getName().equals(methodName))
{
method = m;
break;
}
}
if (method == null)
{
throw new AlfrescoRuntimeException("Method not found: "+methodName);
}
String queryExecutionId = (parameters.getQueryExecutionId() == null ? super.getQueryExecutionId(parameters) : parameters.getQueryExecutionId());
final GetBlogPostsCannedQuery cq = new GetBlogPostsCannedQuery(rawNodeService, methodSecurityInterceptor, method, parameters, queryExecutionId);
return (CannedQuery<BlogPostInfo>) cq;
}
public CannedQuery<BlogPostInfo> getGetDraftsCannedQuery(NodeRef blogContainerNode, String username, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
//FIXME Need tenant service like for GetChildren?
boolean isPublished = false;
List<QName> requiredAspects = null;
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
username,
isPublished,
null, null,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_CREATED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
public CannedQuery<BlogPostInfo> getGetPublishedExternallyCannedQuery(NodeRef blogContainerNode, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
boolean isPublished = true;
List<QName> requiredAspects = Arrays.asList(new QName[]{BlogIntegrationModel.ASPECT_BLOG_POST});
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
null,
isPublished,
null, null,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(BlogIntegrationModel.PROP_POSTED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
public CannedQuery<BlogPostInfo> getGetPublishedCannedQuery(NodeRef blogContainerNode, Date fromDate, Date toDate, String byUser, PagingRequest pagingReq)
{
ParameterCheck.mandatory("blogContainerNode", blogContainerNode);
ParameterCheck.mandatory("pagingReq", pagingReq);
int requestTotalCountMax = pagingReq.getRequestTotalCountMax();
boolean isPublished = true;
List<QName> requiredAspects = null;
GetBlogPostsCannedQueryParams paramBean = new GetBlogPostsCannedQueryParams(blogContainerNode,
byUser,
isPublished,
fromDate, toDate,
requiredAspects);
CannedQueryPageDetails cqpd = createCQPageDetails(pagingReq);
CannedQuerySortDetails cqsd = createCQSortDetails(ContentModel.PROP_PUBLISHED, SortOrder.DESCENDING);
// create query params holder
CannedQueryParameters params = new CannedQueryParameters(paramBean, cqpd, cqsd, AuthenticationUtil.getRunAsUser(), requestTotalCountMax, pagingReq.getQueryExecutionId());
// return canned query instance
return getCannedQuery(params);
}
private CannedQuerySortDetails createCQSortDetails(QName sortProp, SortOrder sortOrder)
{
CannedQuerySortDetails cqsd = null;
List<Pair<? extends Object, SortOrder>> sortPairs = new ArrayList<Pair<? extends Object, SortOrder>>();
sortPairs.add(new Pair<QName, SortOrder>(sortProp, sortOrder));
cqsd = new CannedQuerySortDetails(sortPairs);
return cqsd;
}
private CannedQueryPageDetails createCQPageDetails(PagingRequest pagingReq)
{
int skipCount = pagingReq.getSkipCount();
if (skipCount == -1)
{
skipCount = CannedQueryPageDetails.DEFAULT_SKIP_RESULTS;
}
int maxItems = pagingReq.getMaxItems();
if (maxItems == -1)
{
maxItems = CannedQueryPageDetails.DEFAULT_PAGE_SIZE;
}
// page details
CannedQueryPageDetails cqpd = new CannedQueryPageDetails(skipCount, maxItems, CannedQueryPageDetails.DEFAULT_PAGE_NUMBER, CannedQueryPageDetails.DEFAULT_PAGE_COUNT);
return cqpd;
}
@Override
public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
PropertyCheck.mandatory(this, "methodSecurityInterceptor", methodSecurityInterceptor);
PropertyCheck.mandatory(this, "methodService", methodService);
PropertyCheck.mandatory(this, "methodName", methodName);
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Parameter objects for {@link GetBlogPostsCannedQuery}.
*
* @author Neil Mc Erlean
* @since 4.0
*/
public class GetBlogPostsCannedQueryParams
{
private final NodeRef blogContainerNode;
private final String cmCreator;
/**
* <tt>true</tt> means the blog-posts should be cm:published, <tt>false</tt> means they should not.
*/
private final boolean isPublished;
private final Date publishedFromDate;
private final Date publishedToDate;
private final List<QName> requiredAspects;
public GetBlogPostsCannedQueryParams(NodeRef blogContainerNodeRef,
String cmCreator,
boolean isPublished,
Date publishedFromDate,
Date publishedToDate,
List<QName> requiredAspects)
{
this.blogContainerNode = blogContainerNodeRef;
this.cmCreator = cmCreator;
this.isPublished = isPublished;
this.publishedFromDate = publishedFromDate;
this.publishedToDate = publishedToDate;
if (requiredAspects == null)
{
requiredAspects = Collections.emptyList();
}
this.requiredAspects = requiredAspects;
}
public NodeRef getBlogContainerNode()
{
return blogContainerNode;
}
public String getCmCreator()
{
return cmCreator;
}
public boolean getIsPublished()
{
return this.isPublished;
}
public Date getPublishedFromDate()
{
return publishedFromDate;
}
public Date getPublishedToDate()
{
return publishedToDate;
}
public List<QName> getRequiredAspects()
{
return Collections.unmodifiableList(this.requiredAspects);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.blog.cannedqueries;
import java.util.Comparator;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
/**
* Utility class to sort {@link BlogPostInfo}s on the basis of a Comparable property.
* Comparisons of two null properties are considered 'equal' by this comparator.
* Comparisons involving one null and one non-null property will return the null property as
* being 'before' the non-null property.
*
* Note that it is the responsibility of the calling code to ensure that the specified
* property values actually implement Comparable themselves.
*/
class PropertyBasedComparator implements Comparator<BlogPostInfo>
{
private QName comparableProperty;
private NodeService nodeService;
public PropertyBasedComparator(QName comparableProperty, NodeService nodeService)
{
this.comparableProperty = comparableProperty;
this.nodeService = nodeService;
}
@SuppressWarnings("unchecked")
@Override
public int compare(BlogPostInfo nr1, BlogPostInfo nr2)
{
Comparable prop1 = (Comparable) nodeService.getProperty(nr1.getNodeRef(), comparableProperty);
Comparable prop2 = (Comparable) nodeService.getProperty(nr2.getNodeRef(), comparableProperty);
if (prop1 == null && prop2 == null)
{
return 0;
}
else if (prop1 == null && prop2 != null)
{
return -1;
}
else if (prop1 != null && prop2 == null)
{
return 1;
}
else
{
return prop1.compareTo(prop2);
}
}
}

View File

@@ -30,6 +30,7 @@ import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.forms.FormService;
import org.alfresco.repo.imap.ImapService;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.ActionService;
@@ -327,6 +328,13 @@ public class MockedTestServiceRegistry implements ServiceRegistry
}
public NodeLocatorService getNodeLocatorService()
{
// TODO Auto-generated method stub
return null;
}
public FileFolderService getFileFolderService()
{
// TODO Auto-generated method stub

View File

@@ -39,6 +39,7 @@ import org.alfresco.cmis.CMISResultSet;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.query.PagingResults;
import org.alfresco.query.PermissionedResults;
import org.alfresco.repo.blog.BlogPostInfo;
import org.alfresco.repo.search.SimpleResultSetMetaData;
import org.alfresco.repo.search.impl.lucene.PagingLuceneResultSet;
import org.alfresco.repo.search.impl.lucene.SolrJSONResultSet;
@@ -952,6 +953,10 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
{
testNodeRef = ((FileInfo) nextObject).getNodeRef();
}
else if (BlogPostInfo.class.isAssignableFrom(nextObject.getClass()))
{
testNodeRef = ((BlogPostInfo) nextObject).getNodeRef();
}
else if (Pair.class.isAssignableFrom(nextObject.getClass()))
{
testNodeRef = (NodeRef) ((Pair)nextObject).getSecond();
@@ -960,7 +965,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
{
throw new ACLEntryVoterException(
"The specified parameter is not a collection of " +
"NodeRefs, ChildAssociationRefs, FileInfos or Pair<Long, NodeRef>");
"StoreRefs, NodeRefs, ChildAssociationRefs, FileInfos, BlogPostInfos or Pair<Long, NodeRef>");
}
}
else if (cad.typeString.equals(AFTER_ACL_PARENT))

View File

@@ -28,6 +28,7 @@ import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.forms.FormService;
import org.alfresco.repo.imap.ImapService;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.ActionService;
@@ -532,7 +533,16 @@ public class ServiceDescriptorRegistry
{
return (RatingService)getService(RATING_SERVICE);
}
/*
* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getNodeLocatorService()
*/
public NodeLocatorService getNodeLocatorService()
{
return (NodeLocatorService)getService(NODE_LOCATOR_SERVICE);
}
/* (non-Javadoc)
* @see org.alfresco.service.ServiceRegistry#getInvitationService()
*/

View File

@@ -28,6 +28,7 @@ import org.alfresco.repo.admin.SysAdminParams;
import org.alfresco.repo.forms.FormService;
import org.alfresco.repo.imap.ImapService;
import org.alfresco.repo.lock.JobLockService;
import org.alfresco.repo.nodelocator.NodeLocatorService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.admin.RepoAdminService;
@@ -136,6 +137,7 @@ public interface ServiceRegistry
static final QName RENDITION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RenditionService");
static final QName RATING_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RatingService");
static final QName REPO_ADMIN_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RepoAdminService");
static final QName NODE_LOCATOR_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NodeLocatorService");
// WCM / AVM
static final QName AVM_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AVMService");
@@ -508,6 +510,13 @@ public interface ServiceRegistry
@NotAuditable
RatingService getRatingService();
/**
* Get the node locator service (or null if one is not provided)
* @return
*/
@NotAuditable
NodeLocatorService getNodeLocatorService();
/**
* Get the invitation service (or null if one is not provided)
* @return the invitation service