Activity Service - improve feed cleaner test and fix ALFCOM-2838

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14183 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2009-05-05 10:54:04 +00:00
parent 3e3098f376
commit 52c9a7e5cf
8 changed files with 500 additions and 302 deletions

View File

@@ -2,19 +2,26 @@
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans> <beans>
<bean id="activityService" class="org.alfresco.repo.activities.ActivityServiceImpl"> <!-- Note: ActivityService / FeedGenerator -> SiteService -> ActivityPostService -->
<bean id="activityPostService" class="org.alfresco.repo.activities.ActivityPostServiceImpl">
<property name="postDAO" ref="postDAO"/> <property name="postDAO" ref="postDAO"/>
<property name="tenantService" ref="tenantService"/>
<property name="userNamesAreCaseSensitive" value="${user.name.caseSensitive}"/>
</bean>
<bean id="activityService" class="org.alfresco.repo.activities.ActivityServiceImpl">
<property name="feedDAO" ref="feedDAO"/> <property name="feedDAO" ref="feedDAO"/>
<property name="feedControlDAO" ref="feedControlDAO"/> <property name="feedControlDAO" ref="feedControlDAO"/>
<property name="authorityService" ref="AuthorityService"/> <property name="authorityService" ref="AuthorityService"/>
<property name="tenantService" ref="tenantService"/> <property name="tenantService" ref="tenantService"/>
<property name="siteService" ref="siteService"/> <property name="siteService" ref="siteService"/>
<property name="activityPostService" ref="activityPostService"/>
<property name="userNamesAreCaseSensitive" value="${user.name.caseSensitive}"/> <property name="userNamesAreCaseSensitive" value="${user.name.caseSensitive}"/>
<property name="feedGenerator" ref="feedGenerator"/>
<property name="maxFeedItems" value="${activities.feed.max.size}"/> <property name="maxFeedItems" value="${activities.feed.max.size}"/>
</bean> </bean>
<!-- cleans out-of-date feed entries --> <!-- cleans out-of-date feed entries -->
<bean id="feedCleaner" class="org.alfresco.repo.activities.feed.cleanup.FeedCleaner"> <bean id="feedCleaner" class="org.alfresco.repo.activities.feed.cleanup.FeedCleaner">
<property name="feedDAO" ref="feedDAO"/> <property name="feedDAO" ref="feedDAO"/>
@@ -50,6 +57,7 @@
<property name="repoEndPoint" value="${repo.remote.endpoint.url}"/> <property name="repoEndPoint" value="${repo.remote.endpoint.url}"/>
<property name="userNamesAreCaseSensitive" value="${user.name.caseSensitive}"/> <property name="userNamesAreCaseSensitive" value="${user.name.caseSensitive}"/>
<property name="maxItemsPerCycle" value="100"/> <property name="maxItemsPerCycle" value="100"/>
<property name="activityPostServiceImpl" ref="activityPostService"/>
</bean> </bean>

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.activities;
import java.sql.SQLException;
import java.util.Date;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.domain.activities.ActivityPostDAO;
import org.alfresco.repo.domain.activities.ActivityPostEntity;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.activities.ActivityPostService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Activity Post Service Implementation
*
* @author janv
*/
public class ActivityPostServiceImpl implements ActivityPostService
{
private static final Log logger = LogFactory.getLog(ActivityServiceImpl.class);
private static final int MAX_LEN_USER_ID = 255; // needs to match schema: feed_user_id, post_user_id
private static final int MAX_LEN_SITE_ID = 255; // needs to match schema: site_network
private static final int MAX_LEN_ACTIVITY_TYPE = 255; // needs to match schema: activity_type
private static final int MAX_LEN_ACTIVITY_DATA = 4000; // needs to match schema: activity_data
private static final int MAX_LEN_APP_TOOL_ID = 36; // needs to match schema: app_tool
private ActivityPostDAO postDAO;
private TenantService tenantService;
private int estGridSize = 1;
private boolean userNamesAreCaseSensitive = false;
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
}
public void setPostDAO(ActivityPostDAO postDAO)
{
this.postDAO = postDAO;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEstimatedGridSize(int estGridSize)
{
this.estGridSize = estGridSize;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/
public void postActivity(String activityType, String siteId, String appTool, String activityData)
{
postActivity(activityType, siteId, appTool, activityData, ActivityPostEntity.STATUS.PENDING);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.NodeRef)
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
.append("\"name\":\"").append(name).append("\"")
.append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, org.alfresco.service.cmr.repository.NodeRef, java.lang.String, org.alfresco.service.namespace.QName, org.alfresco.service.cmr.repository.NodeRef)
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name, QName typeQName, NodeRef parentNodeRef)
{
// primarily for delete node activities - eg. delete document, delete folder
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("typeQName", typeQName);
ParameterCheck.mandatory("parentNodeRef", parentNodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
.append("\"name\":\"").append(name).append("\"").append(",")
.append("\"typeQName\":\"").append(typeQName.toPrefixString()).append("\"").append(",") // TODO toPrefixString does not return prefix ??!!
.append("\"parentNodeRef\":\"").append(parentNodeRef.toString()).append("\"")
.append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
}
private void postActivity(String activityType, String siteId, String appTool, String activityData, ActivityPostEntity.STATUS status)
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
try
{
// optional - default to empty string
if (siteId == null)
{
siteId = "";
}
else if (siteId.length() > MAX_LEN_SITE_ID)
{
throw new AlfrescoRuntimeException("Invalid siteId - exceeds " + MAX_LEN_SITE_ID + " chars: " + siteId);
}
// optional - default to empty string
if (appTool == null)
{
appTool = "";
}
else if (appTool.length() > MAX_LEN_APP_TOOL_ID)
{
throw new AlfrescoRuntimeException("Invalid app tool - exceeds " + MAX_LEN_APP_TOOL_ID + " chars: " + appTool);
}
// required
ParameterCheck.mandatoryString("activityType", activityType);
if (activityType.length() > MAX_LEN_ACTIVITY_TYPE)
{
throw new AlfrescoRuntimeException("Invalid activity type - exceeds " + MAX_LEN_ACTIVITY_TYPE + " chars: " + activityType);
}
// optional - default to empty string
if (activityData == null)
{
activityData = "";
}
else if (activityType.length() > MAX_LEN_ACTIVITY_DATA)
{
throw new AlfrescoRuntimeException("Invalid activity data - exceeds " + MAX_LEN_ACTIVITY_DATA + " chars: " + activityData);
}
// required
ParameterCheck.mandatoryString("currentUser", currentUser);
if (currentUser.length() > MAX_LEN_USER_ID)
{
throw new AlfrescoRuntimeException("Invalid user - exceeds " + MAX_LEN_USER_ID + " chars: " + currentUser);
}
else if ((! currentUser.equals(AuthenticationUtil.SYSTEM_USER_NAME)) && (! userNamesAreCaseSensitive))
{
// user names are not case-sensitive
currentUser = currentUser.toLowerCase();
}
}
catch (AlfrescoRuntimeException e)
{
// log error and throw exception
logger.error(e);
throw e;
}
try
{
Date postDate = new Date();
ActivityPostEntity activityPost = new ActivityPostEntity();
activityPost.setUserId(currentUser);
activityPost.setSiteNetwork(tenantService.getName(siteId));
activityPost.setAppTool(appTool);
activityPost.setActivityData(activityData);
activityPost.setActivityType(activityType);
activityPost.setPostDate(postDate);
activityPost.setStatus(status.toString());
activityPost.setLastModified(postDate);
// hash the userid to generate a job task node
int nodeCount = estGridSize;
int userHashCode = currentUser.hashCode();
int nodeHash = (userHashCode % nodeCount) + 1;
activityPost.setJobTaskNode(nodeHash);
try
{
long postId = postDAO.insertPost(activityPost);
if (logger.isDebugEnabled())
{
activityPost.setId(postId);
logger.debug("Posted: " + activityPost);
}
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to post activity: " + e, e);
}
catch (Throwable t)
{
throw new AlfrescoRuntimeException("Failed to post activity: " + t, t);
}
}
catch (AlfrescoRuntimeException e)
{
// log error, subsume exception (for post activity)
logger.error(e);
}
}
}

View File

@@ -26,20 +26,17 @@ package org.alfresco.repo.activities;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.activities.feed.FeedGenerator;
import org.alfresco.repo.domain.activities.ActivityFeedDAO; import org.alfresco.repo.domain.activities.ActivityFeedDAO;
import org.alfresco.repo.domain.activities.ActivityFeedEntity; import org.alfresco.repo.domain.activities.ActivityFeedEntity;
import org.alfresco.repo.domain.activities.ActivityPostDAO;
import org.alfresco.repo.domain.activities.ActivityPostEntity;
import org.alfresco.repo.domain.activities.FeedControlDAO; import org.alfresco.repo.domain.activities.FeedControlDAO;
import org.alfresco.repo.domain.activities.FeedControlEntity; import org.alfresco.repo.domain.activities.FeedControlEntity;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.activities.ActivityPostService;
import org.alfresco.service.cmr.activities.ActivityService; import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.activities.FeedControl; import org.alfresco.service.cmr.activities.FeedControl;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
@@ -61,20 +58,12 @@ public class ActivityServiceImpl implements ActivityService
{ {
private static final Log logger = LogFactory.getLog(ActivityServiceImpl.class); private static final Log logger = LogFactory.getLog(ActivityServiceImpl.class);
private static final int MAX_LEN_USER_ID = 255; // needs to match schema: feed_user_id, post_user_id
private static final int MAX_LEN_SITE_ID = 255; // needs to match schema: site_network
private static final int MAX_LEN_ACTIVITY_TYPE = 255; // needs to match schema: activity_type
private static final int MAX_LEN_ACTIVITY_DATA = 4000; // needs to match schema: activity_data
private static final int MAX_LEN_APP_TOOL_ID = 36; // needs to match schema: app_tool
private ActivityPostDAO postDAO;
private ActivityFeedDAO feedDAO; private ActivityFeedDAO feedDAO;
private FeedControlDAO feedControlDAO; private FeedControlDAO feedControlDAO;
private AuthorityService authorityService; private AuthorityService authorityService;
private FeedGenerator feedGenerator;
private SiteService siteService;
private TenantService tenantService; private TenantService tenantService;
private SiteService siteService;
private ActivityPostService activityPostService;
private int maxFeedItems = 100; private int maxFeedItems = 100;
@@ -90,11 +79,6 @@ public class ActivityServiceImpl implements ActivityService
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive; this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
} }
public void setPostDAO(ActivityPostDAO postDAO)
{
this.postDAO = postDAO;
}
public void setFeedDAO(ActivityFeedDAO feedDAO) public void setFeedDAO(ActivityFeedDAO feedDAO)
{ {
this.feedDAO = feedDAO; this.feedDAO = feedDAO;
@@ -110,11 +94,6 @@ public class ActivityServiceImpl implements ActivityService
this.authorityService = authorityService; this.authorityService = authorityService;
} }
public void setFeedGenerator(FeedGenerator feedGenerator)
{
this.feedGenerator = feedGenerator;
}
public void setTenantService(TenantService tenantService) public void setTenantService(TenantService tenantService)
{ {
this.tenantService = tenantService; this.tenantService = tenantService;
@@ -125,13 +104,19 @@ public class ActivityServiceImpl implements ActivityService
this.siteService = siteService; this.siteService = siteService;
} }
public void setActivityPostService(ActivityPostService activityPostService)
{
this.activityPostService = activityPostService;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, java.lang.String) * @see org.alfresco.service.cmr.activities.ActivityService#postActivity(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/ */
public void postActivity(String activityType, String siteId, String appTool, String activityData) public void postActivity(String activityType, String siteId, String appTool, String activityData)
{ {
postActivity(activityType, siteId, appTool, activityData, ActivityPostEntity.STATUS.PENDING); // delegate
activityPostService.postActivity(activityType, siteId, appTool, activityData);
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -139,12 +124,8 @@ public class ActivityServiceImpl implements ActivityService
*/ */
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef) public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); // delegate
activityPostService.postActivity(activityType, siteId, appTool, nodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -152,14 +133,8 @@ public class ActivityServiceImpl implements ActivityService
*/ */
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name) public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name)
{ {
ParameterCheck.mandatory("nodeRef", nodeRef); // delegate
activityPostService.postActivity(activityType, siteId, appTool, nodeRef, name);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
.append("\"name\":\"").append(name).append("\"")
.append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -167,132 +142,8 @@ public class ActivityServiceImpl implements ActivityService
*/ */
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name, QName typeQName, NodeRef parentNodeRef) public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name, QName typeQName, NodeRef parentNodeRef)
{ {
// primarily for delete node activities - eg. delete document, delete folder // delegate
activityPostService.postActivity(activityType, siteId, appTool, nodeRef, name, typeQName, parentNodeRef);
ParameterCheck.mandatory("nodeRef", nodeRef);
ParameterCheck.mandatory("typeQName", typeQName);
ParameterCheck.mandatory("parentNodeRef", parentNodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
.append("\"name\":\"").append(name).append("\"").append(",")
.append("\"typeQName\":\"").append(typeQName.toPrefixString()).append("\"").append(",") // TODO toPrefixString does not return prefix ??!!
.append("\"parentNodeRef\":\"").append(parentNodeRef.toString()).append("\"")
.append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
}
private void postActivity(String activityType, String siteId, String appTool, String activityData, ActivityPostEntity.STATUS status)
{
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
try
{
// optional - default to empty string
if (siteId == null)
{
siteId = "";
}
else if (siteId.length() > MAX_LEN_SITE_ID)
{
throw new AlfrescoRuntimeException("Invalid siteId - exceeds " + MAX_LEN_SITE_ID + " chars: " + siteId);
}
// optional - default to empty string
if (appTool == null)
{
appTool = "";
}
else if (appTool.length() > MAX_LEN_APP_TOOL_ID)
{
throw new AlfrescoRuntimeException("Invalid app tool - exceeds " + MAX_LEN_APP_TOOL_ID + " chars: " + appTool);
}
// required
ParameterCheck.mandatoryString("activityType", activityType);
if (activityType.length() > MAX_LEN_ACTIVITY_TYPE)
{
throw new AlfrescoRuntimeException("Invalid activity type - exceeds " + MAX_LEN_ACTIVITY_TYPE + " chars: " + activityType);
}
// optional - default to empty string
if (activityData == null)
{
activityData = "";
}
else if (activityType.length() > MAX_LEN_ACTIVITY_DATA)
{
throw new AlfrescoRuntimeException("Invalid activity data - exceeds " + MAX_LEN_ACTIVITY_DATA + " chars: " + activityData);
}
// required
ParameterCheck.mandatoryString("currentUser", currentUser);
if (currentUser.length() > MAX_LEN_USER_ID)
{
throw new AlfrescoRuntimeException("Invalid user - exceeds " + MAX_LEN_USER_ID + " chars: " + currentUser);
}
else if ((! currentUser.equals(AuthenticationUtil.SYSTEM_USER_NAME)) && (! userNamesAreCaseSensitive))
{
// user names are not case-sensitive
currentUser = currentUser.toLowerCase();
}
}
catch (AlfrescoRuntimeException e)
{
// log error and throw exception
logger.error(e);
throw e;
}
try
{
Date postDate = new Date();
ActivityPostEntity activityPost = new ActivityPostEntity();
activityPost.setUserId(currentUser);
activityPost.setSiteNetwork(tenantService.getName(siteId));
activityPost.setAppTool(appTool);
activityPost.setActivityData(activityData);
activityPost.setActivityType(activityType);
activityPost.setPostDate(postDate);
activityPost.setStatus(status.toString());
activityPost.setLastModified(postDate);
// hash the userid to generate a job task node
int nodeCount = feedGenerator.getEstimatedGridSize();
int userHashCode = currentUser.hashCode();
int nodeHash = (userHashCode % nodeCount) + 1;
activityPost.setJobTaskNode(nodeHash);
try
{
long postId = postDAO.insertPost(activityPost);
if (logger.isDebugEnabled())
{
activityPost.setId(postId);
logger.debug("Posted: " + activityPost);
}
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to post activity: " + e, e);
}
catch (Throwable t)
{
throw new AlfrescoRuntimeException("Failed to post activity: " + t, t);
}
}
catch (AlfrescoRuntimeException e)
{
// log error, subsume exception (for post activity)
logger.error(e);
}
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2008 Alfresco Software Limited. * Copyright (C) 2005-2009 Alfresco Software Limited.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@@ -24,6 +24,7 @@
*/ */
package org.alfresco.repo.activities.feed; package org.alfresco.repo.activities.feed;
import org.alfresco.repo.activities.ActivityPostServiceImpl;
import org.alfresco.repo.domain.activities.ActivityPostDAO; import org.alfresco.repo.domain.activities.ActivityPostDAO;
import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
@@ -44,6 +45,7 @@ public abstract class AbstractFeedGenerator implements FeedGenerator
private int maxItemsPerCycle = 100; private int maxItemsPerCycle = 100;
private ActivityPostDAO postDAO; private ActivityPostDAO postDAO;
private ActivityPostServiceImpl activityPostServiceImpl;
private AuthenticationService authenticationService; private AuthenticationService authenticationService;
private String repoEndPoint; // http://hostname:port/webapp (eg. http://localhost:8080/alfresco) private String repoEndPoint; // http://hostname:port/webapp (eg. http://localhost:8080/alfresco)
@@ -54,6 +56,11 @@ public abstract class AbstractFeedGenerator implements FeedGenerator
private volatile boolean busy; private volatile boolean busy;
public void setActivityPostServiceImpl(ActivityPostServiceImpl activityPostServiceImpl)
{
this.activityPostServiceImpl = activityPostServiceImpl;
}
public void setPostDAO(ActivityPostDAO postDAO) public void setPostDAO(ActivityPostDAO postDAO)
{ {
this.postDAO = postDAO; this.postDAO = postDAO;
@@ -112,9 +119,12 @@ public abstract class AbstractFeedGenerator implements FeedGenerator
*/ */
private void checkProperties() private void checkProperties()
{ {
PropertyCheck.mandatory(this, "postDAO", postDAO); PropertyCheck.mandatory(this, "postDAO", postDAO);
activityPostServiceImpl.setEstimatedGridSize(getEstimatedGridSize());
} }
abstract public int getEstimatedGridSize();
public void execute() throws JobExecutionException public void execute() throws JobExecutionException
{ {

View File

@@ -24,8 +24,9 @@
*/ */
package org.alfresco.repo.activities.feed.cleanup; package org.alfresco.repo.activities.feed.cleanup;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CountDownLatch;
import junit.framework.TestCase; import junit.framework.TestCase;
@@ -33,6 +34,8 @@ import org.alfresco.repo.domain.activities.ActivityFeedDAO;
import org.alfresco.repo.domain.activities.ActivityFeedEntity; import org.alfresco.repo.domain.activities.ActivityFeedEntity;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.activities.ActivityService; import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
@@ -48,16 +51,23 @@ public class FeedCleanerTest extends TestCase
private ActivityFeedDAO feedDAO; private ActivityFeedDAO feedDAO;
private FeedCleaner cleaner; private FeedCleaner cleaner;
private ActivityService activityService; private ActivityService activityService;
private SiteService siteService;
@Override @Override
public void setUp() throws Exception public void setUp() throws Exception
{ {
activityService = (ActivityService) ctx.getBean("activityService");
siteService = (SiteService) ctx.getBean("SiteService");
feedDAO = (ActivityFeedDAO) ctx.getBean("feedDAO");
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
for (int i = 1; i <= 7; i++)
{
siteService.createSite("myPreset", "testSite"+i, null, null, SiteVisibility.PUBLIC);
}
AuthenticationUtil.setRunAsUserSystem(); AuthenticationUtil.setRunAsUserSystem();
activityService = (ActivityService) ctx.getBean("activityService");
feedDAO = (ActivityFeedDAO) ctx.getBean("feedDAO");
// construct the test cleaner // construct the test cleaner
cleaner = new FeedCleaner(); cleaner = new FeedCleaner();
cleaner.setFeedDAO(feedDAO); cleaner.setFeedDAO(feedDAO);
@@ -66,7 +76,12 @@ public class FeedCleanerTest extends TestCase
public void tearDown() throws Exception public void tearDown() throws Exception
{ {
// clean out any remaining feed entries (allows test to be re-runnable) // clean out any remaining feed entries (allows test to be re-runnable)
feedDAO.deleteFeedEntries(new Date(System.currentTimeMillis()+(120*1000L))); feedDAO.deleteFeedEntries(new Date(System.currentTimeMillis()+(120*1000L)));
for (int i = 1; i <= 7; i++)
{
siteService.deleteSite("testSite"+i);
}
AuthenticationUtil.clearCurrentSecurityContext(); AuthenticationUtil.clearCurrentSecurityContext();
} }
@@ -244,72 +259,107 @@ public class FeedCleanerTest extends TestCase
cleaner.setMaxAgeMins(1); cleaner.setMaxAgeMins(1);
cleaner.setMaxFeedSize(1); cleaner.setMaxFeedSize(1);
final int typeCount = 3; int typeCount = 3;
int threadCount = typeCount * 10; int n = typeCount * 10;
final CountDownLatch endLatch = new CountDownLatch(threadCount); Thread[] threads = new Thread[n];
// Kick off the threads Tester[] testers = new Tester[n];
for (int i = 0; i < threadCount; i++)
for (int i = 0; i < n; i++)
{ {
Thread thread = new Thread(""+i) Tester tester = new Tester(i, typeCount);
{ testers[i] = tester;
@Override
public void run() threads[i] = new Thread(tester);
{ threads[i].start();
try }
{ for (int i = 0; i < n; i++)
int type = new Integer(this.getName()) % typeCount; {
threads[i].join();
if (type == 0)
{ if (testers[i].getErrorStackTrace() != null)
int insertCount = 10; {
fail(testers[i].getErrorStackTrace());
// insert some entries }
for (int i = 0; i < insertCount; i++) }
{ }
ActivityFeedEntity feedEntry = new ActivityFeedEntity();
private class Tester implements Runnable
feedEntry.setPostDate(new Date(System.currentTimeMillis()-(i*60*1000L))); {
feedEntry.setActivitySummaryFormat("json"); private int i;
feedEntry.setSiteNetwork("testSite4"); private int typeCount;
feedEntry.setActivityType("testActivityType"); private String errorStackTrace = null;
feedEntry.setPostUserId("testUserC");
feedEntry.setFeedUserId(""); public Tester(int i, int typeCount)
feedEntry.setFeedDate(new Date()); {
this.i = i;
feedDAO.insertFeedEntry(feedEntry); this.typeCount = typeCount;
} }
System.out.println("["+this.getName()+"] Inserted "+insertCount+" entries"); public String getErrorStackTrace()
} {
return errorStackTrace;
if (type == 1) }
{
// query some entries public void run()
int selectCount = activityService.getSiteFeedEntries("testSite4", "json").size(); {
try
System.out.println("["+this.getName()+"] Selected "+selectCount+" entries"); {
} int type = i % typeCount;
if (type == 2) if (type == 0)
{ {
// clean some entries AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
int deleteCount = cleaner.execute();
int insertCount = 10;
System.out.println("["+this.getName()+"] Deleted "+deleteCount+" entries");
} // insert some entries
} for (int i = 0; i < insertCount; i++)
catch (Exception e) {
{ ActivityFeedEntity feedEntry = new ActivityFeedEntity();
fail(e.getMessage());
} feedEntry.setPostDate(new Date(System.currentTimeMillis()-(i*60*1000L)));
// Notify of completion feedEntry.setActivitySummaryFormat("json");
endLatch.countDown(); feedEntry.setSiteNetwork("testSite4");
} feedEntry.setActivityType("testActivityType");
}; feedEntry.setPostUserId("testUserC");
thread.start(); feedEntry.setFeedUserId("");
feedEntry.setFeedDate(new Date());
feedDAO.insertFeedEntry(feedEntry);
}
System.out.println("["+i+"] Inserted "+insertCount+" entries");
}
if (type == 1)
{
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
// query some entries
int selectCount = activityService.getSiteFeedEntries("testSite4", "json").size();
System.out.println("["+i+"] Selected "+selectCount+" entries");
}
if (type == 2)
{
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
// clean some entries
int deleteCount = cleaner.execute();
System.out.println("["+i+"] Deleted "+deleteCount+" entries");
}
}
catch (Throwable t)
{
StringWriter sw = new StringWriter();
t.printStackTrace(new PrintWriter(sw));
errorStackTrace = sw.toString();
fail(t.getMessage());
}
} }
// Wait for them all to be done
endLatch.await();
} }
} }

View File

@@ -49,6 +49,7 @@ public class LocalFeedGenerator extends AbstractFeedGenerator
this.feedTaskProcessor = feedTaskProcessor; this.feedTaskProcessor = feedTaskProcessor;
} }
@Override
public int getEstimatedGridSize() public int getEstimatedGridSize()
{ {
return 1; return 1;

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.service.cmr.activities;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
public interface ActivityPostService
{
/*
* Post Activity
*/
/**
* Post a custom activity type
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param jsonActivityData - required
*/
public void postActivity(String activityType, String siteId, String appTool, String jsonActivityData);
/**
* Post a pre-defined activity type - certain activity data will be looked-up asynchronously, including:
*
* name (of nodeRef)
* displayPath
* typeQName
* firstName (of posting user)
* lastName (of posting user)
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - do not use for deleted (or about to be deleted) nodeRef
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef);
/**
* Post a pre-defined activity type - eg. for checked-out nodeRef or renamed nodeRef
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - do not use deleted (or about to be deleted) nodeRef
* @param beforeName - optional - name of node (eg. prior to name change)
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String beforeName);
/**
* Post a pre-defined activity type - eg. for deleted nodeRef
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - can be a deleted (or about to be deleted) nodeRef
* @param name - optional - name of name
* @param typeQName - optional - type of node
* @param parentNodeRef - required - used to lookup path/displayPath
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name, QName typeQName, NodeRef parentNodeRef);
}

View File

@@ -26,67 +26,8 @@ package org.alfresco.service.cmr.activities;
import java.util.List; import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef; public interface ActivityService extends ActivityPostService
import org.alfresco.service.namespace.QName; {
public interface ActivityService
{
/*
* Post Activity
*/
/**
* Post a custom activity type
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param jsonActivityData - required
*/
public void postActivity(String activityType, String siteId, String appTool, String jsonActivityData);
/**
* Post a pre-defined activity type - certain activity data will be looked-up asynchronously, including:
*
* name (of nodeRef)
* displayPath
* typeQName
* firstName (of posting user)
* lastName (of posting user)
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - do not use for deleted (or about to be deleted) nodeRef
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef);
/**
* Post a pre-defined activity type - eg. for checked-out nodeRef or renamed nodeRef
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - do not use deleted (or about to be deleted) nodeRef
* @param beforeName - optional - name of node (eg. prior to name change)
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String beforeName);
/**
* Post a pre-defined activity type - eg. for deleted nodeRef
*
* @param activityType - required
* @param siteId - optional, if null will be stored as empty string
* @param appTool - optional, if null will be stored as empty string
* @param nodeRef - required - can be a deleted (or about to be deleted) nodeRef
* @param name - optional - name of name
* @param typeQName - optional - type of node
* @param parentNodeRef - required - used to lookup path/displayPath
*/
public void postActivity(String activityType, String siteId, String appTool, NodeRef nodeRef, String name, QName typeQName, NodeRef parentNodeRef);
/* /*
* Retrieve Feed Entries * Retrieve Feed Entries
*/ */