First-cut Activity Service (SLNG-20)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9128 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2008-05-15 16:34:11 +00:00
parent 9e67621ace
commit 067013afad
58 changed files with 5420 additions and 2 deletions

View File

@@ -0,0 +1,511 @@
/*
* Copyright (C) 2005-2008 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.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.activities.feed.ActivityFeedDAO;
import org.alfresco.repo.activities.feed.ActivityFeedDaoService;
import org.alfresco.repo.activities.feed.FeedGenerator;
import org.alfresco.repo.activities.feed.control.FeedControlDAO;
import org.alfresco.repo.activities.feed.control.FeedControlDaoService;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.activities.FeedControl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.JSONtoFmModel;
import org.alfresco.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
/**
* Activity Service Implementation
*
* @author janv
*/
public class ActivityServiceImpl implements ActivityService
{
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 ActivityPostDaoService postDaoService;
private ActivityFeedDaoService feedDaoService;
private FeedControlDaoService feedControlDaoService;
private AuthorityService authorityService;
private FeedGenerator feedGenerator;
private int maxFeedItems = 100;
private boolean userNamesAreCaseSensitive = false;
public void setMaxFeedItems(int maxFeedItems)
{
this.maxFeedItems = maxFeedItems;
}
public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive)
{
this.userNamesAreCaseSensitive = userNamesAreCaseSensitive;
}
public void setPostDaoService(ActivityPostDaoService postDaoService)
{
this.postDaoService = postDaoService;
}
public void setFeedDaoService(ActivityFeedDaoService feedDaoService)
{
this.feedDaoService = feedDaoService;
}
public void setFeedControlDaoService(FeedControlDaoService feedControlDaoService)
{
this.feedControlDaoService = feedControlDaoService;
}
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
public void setFeedGenerator(FeedGenerator feedGenerator)
{
this.feedGenerator = feedGenerator;
}
/* (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 network, String appTool, String activityData)
{
postActivity(activityType, network, appTool, activityData, ActivityPostDAO.STATUS.POSTED);
}
/* (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 network, String appTool, NodeRef nodeRef)
{
ParameterCheck.mandatory("nodeRef", nodeRef);
StringBuffer sb = new StringBuffer();
sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append("}");
postActivity(activityType, network, appTool, sb.toString(), ActivityPostDAO.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 network, 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, network, appTool, sb.toString(), ActivityPostDAO.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 network, 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, network, appTool, sb.toString(), ActivityPostDAO.STATUS.PENDING);
}
private void postActivity(String activityType, String siteNetwork, String appTool, String activityData, ActivityPostDAO.STATUS status)
{
String currentUser = AuthenticationUtil.getCurrentUserName();
try
{
// optional - default to empty string
if (siteNetwork == null)
{
siteNetwork = "";
}
else if (siteNetwork.length() > MAX_LEN_SITE_ID)
{
throw new AlfrescoRuntimeException("Invalid site network - exceeds " + MAX_LEN_SITE_ID + " chars: " + siteNetwork);
}
// 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 case-insensitive
currentUser = currentUser.toLowerCase();
}
}
catch (AlfrescoRuntimeException e)
{
// log error and throw exception
logger.error(e);
throw e;
}
try
{
Date postDate = new Date();
ActivityPostDAO activityPost = new ActivityPostDAO();
activityPost.setUserId(currentUser);
activityPost.setSiteNetwork(siteNetwork);
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 = postDaoService.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 (AlfrescoRuntimeException e)
{
// log error, subsume exception
logger.error(e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#getUserFeedEntries(java.lang.String, java.lang.String, java.lang.String)
*/
public List<Map<String, Object>> getUserFeedEntries(String feedUserId, String format, String siteId)
{
// NOTE: siteId is optional
ParameterCheck.mandatoryString("feedUserId", feedUserId);
ParameterCheck.mandatoryString("format", format);
List<Map<String, Object>> activityFeedModels = new ArrayList<Map<String, Object>>();
if (! userNamesAreCaseSensitive)
{
feedUserId = feedUserId.toLowerCase();
}
String currentUser = AuthenticationUtil.getCurrentUserName();
if (currentUser != null)
{
if ((! authorityService.isAdminAuthority(currentUser)) && (! currentUser.equals(feedUserId)))
{
throw new AlfrescoRuntimeException("Unable to get feed entries for '" + feedUserId + "' - currently logged in as '" + currentUser +"'");
}
try
{
List<ActivityFeedDAO> activityFeeds = null;
if (siteId != null)
{
activityFeeds = feedDaoService.selectUserFeedEntries(feedUserId, format, siteId);
}
else
{
activityFeeds = feedDaoService.selectUserFeedEntries(feedUserId, format);
}
int count = 0;
for (ActivityFeedDAO activityFeed : activityFeeds)
{
count++;
if (count > maxFeedItems)
{
break;
}
activityFeedModels.add(JSONtoFmModel.convertJSONObjectToMap(activityFeed.getJSONString()));
}
}
catch (SQLException se)
{
throw new AlfrescoRuntimeException("Unable to get user feed entries: " + se.getMessage());
}
catch (JSONException je)
{
throw new AlfrescoRuntimeException("Unable to get user feed entries: " + je.getMessage());
}
}
else
{
throw new AlfrescoRuntimeException("Unable to get user feed entries - current user is null");
}
return activityFeedModels;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#getSiteFeedEntries(java.lang.String, java.lang.String)
*/
public List<Map<String, Object>> getSiteFeedEntries(String siteId, String format)
{
ParameterCheck.mandatoryString("siteId", siteId);
ParameterCheck.mandatoryString("format", format);
List<Map<String, Object>> activityFeedModels = new ArrayList<Map<String, Object>>();
String currentUser = AuthenticationUtil.getCurrentUserName();
if (currentUser != null)
{
// TODO - check whether site is public or private, if private, check whether user is member or admin - authorityService.isAdminAuthority(currentUser))
try
{
List<ActivityFeedDAO> activityFeeds = feedDaoService.selectSiteFeedEntries(siteId, format);
int count = 0;
for (ActivityFeedDAO activityFeed : activityFeeds)
{
count++;
if (count > maxFeedItems)
{
break;
}
activityFeedModels.add(JSONtoFmModel.convertJSONObjectToMap(activityFeed.getJSONString()));
}
}
catch (SQLException se)
{
throw new AlfrescoRuntimeException("Unable to get site feed entries: " + se.getMessage());
}
catch (JSONException je)
{
throw new AlfrescoRuntimeException("Unable to get site feed entries: " + je.getMessage());
}
}
else
{
throw new AlfrescoRuntimeException("Unable to get site feed entries - current user is null");
}
return activityFeedModels;
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#setFeedControl(org.alfresco.service.cmr.activities.FeedControl)
*/
public void setFeedControl(FeedControl feedControl)
{
ParameterCheck.mandatory("feedControl", feedControl);
String userId = AuthenticationUtil.getCurrentUserName();
if (! userNamesAreCaseSensitive)
{
userId = userId.toLowerCase();
}
try
{
if (! existsFeedControl(feedControl))
{
feedControlDaoService.insertFeedControl(new FeedControlDAO(userId, feedControl));
}
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to set feed control: " + e, e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#getFeedControls()
*/
public List<FeedControl> getFeedControls()
{
String userId = AuthenticationUtil.getCurrentUserName();
return getFeedControlsImpl(userId);
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#getFeedControls(java.lang.String)
*/
public List<FeedControl> getFeedControls(String userId)
{
ParameterCheck.mandatoryString("userId", userId);
String currentUser = AuthenticationUtil.getCurrentUserName();
if ((currentUser == null) || ((! currentUser.equals(AuthenticationUtil.getSystemUserName())) && (! currentUser.equals(userId)) && (! authorityService.isAdminAuthority(currentUser))))
{
throw new AlfrescoRuntimeException("Current user " + currentUser + " is not permitted to get feed controls for " + userId);
}
return getFeedControlsImpl(userId);
}
private List<FeedControl> getFeedControlsImpl(String userId)
{
ParameterCheck.mandatoryString("userId", userId);
if (! userNamesAreCaseSensitive)
{
userId = userId.toLowerCase();
}
try
{
List<FeedControlDAO> feedControlDaos = feedControlDaoService.selectFeedControls(userId);
List<FeedControl> feedControls = new ArrayList<FeedControl>(feedControlDaos.size());
for (FeedControlDAO feedControlDao : feedControlDaos)
{
feedControls.add(feedControlDao.getFeedControl());
}
return feedControls;
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to set feed control: " + e, e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#deleteFeedControl(org.alfresco.service.cmr.activities.FeedControl)
*/
public void unsetFeedControl(FeedControl feedControl)
{
ParameterCheck.mandatory("feedControl", feedControl);
String userId = AuthenticationUtil.getCurrentUserName();
if (! userNamesAreCaseSensitive)
{
userId = userId.toLowerCase();
}
try
{
feedControlDaoService.deleteFeedControl(new FeedControlDAO(userId, feedControl));
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to set feed control: " + e, e);
}
}
/* (non-Javadoc)
* @see org.alfresco.service.cmr.activities.ActivityService#existsFeedControl(java.lang.String, org.alfresco.service.cmr.activities.FeedControl)
*/
public boolean existsFeedControl(FeedControl feedControl)
{
ParameterCheck.mandatory("feedControl", feedControl);
String userId = AuthenticationUtil.getCurrentUserName();
if (! userNamesAreCaseSensitive)
{
userId = userId.toLowerCase();
}
try
{
long id = feedControlDaoService.selectFeedControl(new FeedControlDAO(userId, feedControl));
return (id != -1);
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to query feed control: " + e, e);
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2005-2008 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.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.jscript.ClasspathScriptLocation;
import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.activities.FeedControl;
import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.BaseSpringTest;
/**
* Activity Service Implementation unit test
*
* @author janv
*/
public class ActivityServiceImplTest extends BaseSpringTest
{
private ActivityService activityService;
private ScriptService scriptService;
private AuthenticationService authenticationService;
private static final String ADMIN_UN = "admin";
private static final String ADMIN_PW = "admin";
private static final String USER_UN = "bob";
private static final String USER_PW = "bob";
protected void onSetUpInTransaction() throws Exception
{
super.onSetUpInTransaction();
// Get the required services
this.activityService = (ActivityService)this.applicationContext.getBean("ActivityService");
this.scriptService = (ScriptService)this.applicationContext.getBean("ScriptService");
this.authenticationService = (AuthenticationService)applicationContext.getBean("authenticationService");
authenticationService.authenticate(ADMIN_UN, ADMIN_PW.toCharArray());
}
protected void onTearDownInTransaction() throws Exception
{
authenticationService.clearCurrentSecurityContext();
}
public void testPostValidActivities() throws Exception
{
this.activityService.postActivity("org.alfresco.testActivityType1", null, null, "");
this.activityService.postActivity("org.alfresco.testActivityType2", "", "", "");
this.activityService.postActivity("org.alfresco.testActivityType3", "site1", "appToolA", "{ \"var1\" : \"val1\" }");
}
public void testPostInvalidActivities() throws Exception
{
try
{
this.activityService.postActivity("", "", "", null, "");
fail("invalid post activity");
}
catch (IllegalArgumentException iae)
{
assertTrue(iae.getMessage().contains("nodeRef is a mandatory parameter"));
}
try
{
this.activityService.postActivity("", "", "", "");
fail("invalid post activity");
}
catch (IllegalArgumentException iae)
{
assertTrue(iae.getMessage().contains("activityType is a mandatory parameter"));
}
}
public void testGetEmptySiteFeed() throws Exception
{
authenticationService.clearCurrentSecurityContext();
if(! authenticationService.authenticationExists(USER_UN))
{
authenticationService.createAuthentication(USER_UN, USER_PW.toCharArray());
}
authenticationService.authenticate(USER_UN, USER_PW.toCharArray());
List<Map<String, Object>> siteFeedEntries = this.activityService.getSiteFeedEntries("unknown site", "some format");
assertNotNull(siteFeedEntries);
assertTrue(siteFeedEntries.isEmpty());
}
public void testGetEmptyUserFeed() throws Exception
{
List<Map<String, Object>> userFeedEntries = this.activityService.getUserFeedEntries("unknown user", "some format", null);
assertNotNull(userFeedEntries);
assertTrue(userFeedEntries.isEmpty());
}
public void testJSAPI() throws Exception
{
ScriptLocation location = new ClasspathScriptLocation("org/alfresco/repo/activities/script/test_activityService.js");
String result = (String)this.scriptService.executeScript(location, new HashMap<String, Object>(0));
// Check the result and fail if message returned
if (result != null && result.length() != 0)
{
fail("The activity service test JS script failed: " + result);
}
}
public void testFeedControls() throws Exception
{
List<FeedControl> feedControls = this.activityService.getFeedControls(USER_UN);
assertNotNull(feedControls);
assertTrue(feedControls.isEmpty());
authenticationService.clearCurrentSecurityContext();
if(! authenticationService.authenticationExists(USER_UN))
{
authenticationService.createAuthentication(USER_UN, USER_PW.toCharArray());
}
authenticationService.authenticate(USER_UN, USER_PW.toCharArray());
feedControls = this.activityService.getFeedControls();
assertNotNull(feedControls);
assertTrue(feedControls.isEmpty());
assertFalse(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1")));
this.activityService.setFeedControl(new FeedControl("mySite1", null));
this.activityService.setFeedControl(new FeedControl("mySite1", "appTool1"));
this.activityService.setFeedControl(new FeedControl(null, "appTool2"));
feedControls = this.activityService.getFeedControls();
assertEquals(3, feedControls.size());
feedControls = this.activityService.getFeedControls(USER_UN);
assertEquals(3, feedControls.size());
assertTrue(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1")));
this.activityService.unsetFeedControl(new FeedControl("mySite1", "appTool1"));
assertFalse(this.activityService.existsFeedControl(new FeedControl("mySite1", "appTool1")));
feedControls = this.activityService.getFeedControls();
assertEquals(2, feedControls.size());
this.activityService.unsetFeedControl(new FeedControl("mySite1", null));
this.activityService.unsetFeedControl(new FeedControl(null, "appTool2"));
feedControls = this.activityService.getFeedControls();
assertEquals(0, feedControls.size());
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2005-2008 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;
public interface ActivityType
{
// pre-defined alfresco activity types
// generic fallback (if specific template is missing)
public final String GENERIC_FALLBACK = "org.alfresco.generic";
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2005-2008 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.feed;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.VmShutdownListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionException;
/**
* Implementations of the abstract feed generator component are responsible for generating activity feed entries
*/
public abstract class AbstractFeedGenerator implements FeedGenerator
{
private static Log logger = LogFactory.getLog(AbstractFeedGenerator.class);
private static VmShutdownListener vmShutdownListener = new VmShutdownListener(AbstractFeedGenerator.class.getName());
private int maxItemsPerCycle = 100;
private ActivityPostDaoService postDaoService;
private AuthenticationService authenticationService;
private String repoEndPoint; // http://hostname:port/webapp (eg. http://localhost:8080/alfresco)
private RepoCtx ctx = null;
private boolean busy;
public void setPostDaoService(ActivityPostDaoService postDaoService)
{
this.postDaoService = postDaoService;
}
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
public void setRepoEndPoint(String repoEndPoint)
{
this.repoEndPoint = repoEndPoint;
}
public void setMaxItemsPerCycle(int maxItemsPerCycle)
{
this.maxItemsPerCycle = maxItemsPerCycle;
}
public int getMaxItemsPerCycle()
{
return this.maxItemsPerCycle;
}
public ActivityPostDaoService getPostDaoService()
{
return this.postDaoService;
}
public AuthenticationService getAuthenticationService()
{
return this.authenticationService;
}
public RepoCtx getWebScriptsCtx()
{
return this.ctx;
}
public void init() throws Exception
{
ctx = new RepoCtx(repoEndPoint);
busy = false;
}
/**
* Perform basic checks to ensure that the necessary dependencies were injected.
*/
private void checkProperties()
{
PropertyCheck.mandatory(this, "postDaoService", postDaoService);
}
public void execute() throws JobExecutionException
{
if (busy)
{
logger.warn("Still busy ...");
return;
}
checkProperties();
try
{
// run at least one job cycle
boolean moreWork = true;
while (moreWork)
{
moreWork = generate();
}
}
catch (Throwable e)
{
// If the VM is shutting down, then ignore
if (vmShutdownListener.isVmShuttingDown())
{
// Ignore
}
else
{
logger.error("Exception during generation of feeds", e);
}
}
finally
{
busy = false;
}
}
protected abstract boolean generate() throws Exception;
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONStringer;
/**
* Activity Feed DAO
*/
public class ActivityFeedDAO
{
private long id; // internal DB-generated id
private String activityType;
private String activitySummary;
private String activitySummaryFormat;
private String feedUserId;
private String postUserId;
private String siteNetwork;
private String appTool;
private Date postDate;
private Date feedDate; // for debug
private long postId; // for debug - not an explicit FK constraint, could be used to implement re-generate
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getActivitySummary()
{
return activitySummary;
}
public void setActivitySummary(String summary)
{
this.activitySummary = summary;
}
public String getFeedUserId()
{
return feedUserId;
}
public void setFeedUserId(String userid)
{
this.feedUserId = userid;
}
public String getPostUserId()
{
return postUserId;
}
public void setPostUserId(String userid)
{
this.postUserId = userid;
}
public String getActivitySummaryFormat()
{
return activitySummaryFormat;
}
public void setActivitySummaryFormat(String format)
{
this.activitySummaryFormat = format;
}
public String getSiteNetwork()
{
return siteNetwork;
}
public void setSiteNetwork(String siteNetwork)
{
this.siteNetwork = siteNetwork;
}
public String getActivityType()
{
return activityType;
}
public void setActivityType(String activityType)
{
this.activityType = activityType;
}
public Date getPostDate()
{
return postDate;
}
public void setPostDate(Date postDate)
{
this.postDate = postDate;
}
public long getPostId()
{
return postId;
}
public void setPostId(long postId)
{
this.postId = postId;
}
public Date getFeedDate()
{
return feedDate;
}
public void setFeedDate(Date feedDate)
{
this.feedDate = feedDate;
}
public String getAppTool()
{
return appTool;
}
public void setAppTool(String appTool)
{
this.appTool = appTool;
}
public String getJSONString() throws JSONException
{
return new JSONStringer()
.object()
.key("postUserId")
.value(postUserId)
.key("postDate")
.value(postDate)
.key("feedUserId")
.value(feedUserId)
.key("siteNetwork")
.value(siteNetwork)
.key("activityType")
.value(activityType)
.key("activitySummary")
.value(activitySummary)
.key("activitySummaryFormat")
.value(activitySummaryFormat)
.endObject().toString();
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import org.alfresco.repo.activities.ibatis.ActivityDaoService;
/**
* Interface for activity feed DAO service
*/
public interface ActivityFeedDaoService extends ActivityDaoService
{
public long insertFeedEntry(ActivityFeedDAO activityFeed) throws SQLException;
public int deleteFeedEntries(Date keepDate) throws SQLException;
public List<ActivityFeedDAO> selectUserFeedEntries(String feedUserId, String format) throws SQLException;
public List<ActivityFeedDAO> selectUserFeedEntries(String feedUserId, String format, String siteId) throws SQLException;
public List<ActivityFeedDAO> selectSiteFeedEntries(String siteUserId, String format) throws SQLException;
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2005-2008 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.feed;
import org.quartz.JobExecutionException;
/**
* Interface for feed generator
*/
public interface FeedGenerator
{
public void execute() throws JobExecutionException;
public int getEstimatedGridSize();
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 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.feed;
import org.alfresco.error.AlfrescoRuntimeException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Executes scheduled feed generator quartz-job - refer to scheduled-jobs-context.xml
*/
public class FeedGeneratorJob implements Job
{
public FeedGeneratorJob()
{
}
/**
* Calls the feed generator to do its work
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap jobData = context.getJobDetail().getJobDataMap();
// extract the feed cleaner to use
Object feedGeneratorObj = jobData.get("feedGenerator");
if (feedGeneratorObj == null || !(feedGeneratorObj instanceof FeedGenerator))
{
throw new AlfrescoRuntimeException(
"FeedGeneratorObj data must contain valid 'feedGenerator' reference");
}
FeedGenerator feedGenerator = (FeedGenerator)feedGeneratorObj;
feedGenerator.execute();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.io.Serializable;
/**
* Interface for feed grid job
*/
public interface FeedGridJob
{
public void setArgument(JobSettings arg);
public JobSettings getArgument();
public Serializable execute() throws Exception;
}

View File

@@ -0,0 +1,636 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.activities.feed.control.FeedControlDAO;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.template.ISO8601DateFormatMethod;
import org.alfresco.util.Base64;
import org.alfresco.util.JSONtoFmModel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import freemarker.cache.URLTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
/**
* Responsible for processing the individual task
*/
public abstract class FeedTaskProcessor
{
private static final Log logger = LogFactory.getLog(FeedTaskProcessor.class);
private static final String defaultFormat = "text";
private static final String[] formats = {"atomentry", "rss", "json", "html", "xml", defaultFormat};
private static final String URL_SERVICE_SITES = "/api/sites";
private static final String URL_MEMBERSHIPS = "/memberships";
private static final String URL_SERVICE_TEMPLATES = "/api/activities/templates";
private static final String URL_SERVICE_TEMPLATE = "/api/activities/template";
public void process(int jobTaskNode, long minSeq, long maxSeq, RepoCtx ctx) throws Exception
{
if (logger.isDebugEnabled())
{
logger.debug(">>> Process: jobTaskNode '" + jobTaskNode + "' from seq '" + minSeq + "' to seq '" + maxSeq + "' on this node from grid job.");
}
ActivityPostDAO selector = new ActivityPostDAO();
selector.setJobTaskNode(jobTaskNode);
selector.setMinId(minSeq);
selector.setMaxId(maxSeq);
selector.setStatus(ActivityPostDAO.STATUS.POSTED.toString());
String ticket = ctx.getTicket();
List<ActivityPostDAO> activityPosts = null;
int totalGenerated = 0;
try
{
activityPosts = selectPosts(selector);
if (logger.isDebugEnabled()) { logger.debug(">>> Process: " + activityPosts.size() + " activity posts"); }
Configuration cfg = getFreemarkerConfiguration(ctx);
Map<String, List<String>> activityTemplates = new HashMap<String, List<String>>(10);
// for each activity post ...
for (ActivityPostDAO activityPost : activityPosts)
{
String postingUserId = activityPost.getUserId();
String activityType = activityPost.getActivityType();
// eg. org.alfresco.folder.added -> added
String baseActivityType = getBaseActivityType(activityType);
List<String> fmTemplates = activityTemplates.get(baseActivityType);
if (fmTemplates == null)
{
// eg. org.alfresco.folder.added -> /org/alfresco/folder/added (note: the leading slash)
String templateSubPath = getTemplateSubPath(activityType);
fmTemplates = new ArrayList<String>(0);
while (true)
{
int idx = templateSubPath.lastIndexOf("/");
if (idx != -1)
{
templateSubPath = templateSubPath.substring(0, idx);
Map<String, List<String>> templates = null;
try
{
// Repository callback to get list of FreeMarker templates for given activity type
templates = getActivityTypeTemplates(ctx.getRepoEndPoint(), ticket, templateSubPath+"/");
}
catch (FileNotFoundException fnfe)
{
// ignore - path does not exist
}
if (templates != null)
{
if (templates.get(baseActivityType) != null)
{
// add templates, if format not already included
addMissingFormats(activityType, fmTemplates, templates.get(baseActivityType));
}
// special fallback case
if (templates.get("generic") != null)
{
// add templates, if format not already included
addMissingFormats(activityType, fmTemplates, templates.get("generic"));
}
}
}
else
{
break;
}
}
activityTemplates.put(baseActivityType, fmTemplates);
}
if (fmTemplates.size() == 0)
{
logger.error(">>> Skipping activity post " + activityPost.getId() + " since no specific/generic templates for activityType: " + activityType );
updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.ERROR);
continue;
}
Map<String, Object> model = null;
try
{
model = JSONtoFmModel.convertJSONObjectToMap(activityPost.getActivityData());
}
catch(JSONException je)
{
logger.error(">>> Skipping activity post " + activityPost.getId() + " due to invalid activity data: " + je);
updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.ERROR);
continue;
}
model.put("activityType", activityPost.getActivityType());
model.put("siteNetwork", activityPost.getSiteNetwork());
model.put("userId", activityPost.getUserId());
model.put("id", activityPost.getId());
model.put("date", activityPost.getPostDate()); // post date rather than time that feed is generated
model.put("xmldate", new ISO8601DateFormatMethod());
model.put("repoEndPoint", ctx.getRepoEndPoint());
Set<String> connectedUsers = null;
if ((activityPost.getSiteNetwork() == null) || (activityPost.getSiteNetwork().length() == 0))
{
connectedUsers = new HashSet<String>(1);
}
else
{
try
{
// Repository callback to get site members
connectedUsers = getSiteMembers(ctx, activityPost.getSiteNetwork());
}
catch(Exception e)
{
logger.error(">>> Skipping activity post " + activityPost.getId() + " since failed to get site members: " + e);
updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.ERROR);
continue;
}
}
connectedUsers.add(""); // add empty posting userid - to represent site feed !
try
{
startTransaction();
if (logger.isDebugEnabled())
{
logger.debug(">>> Process: " + connectedUsers.size() + " candidate connections for activity post " + activityPost.getId());
}
int excludedConnections = 0;
for (String connectedUser : connectedUsers)
{
List<FeedControlDAO> feedControls = null;
if (! connectedUser.equals(""))
{
feedControls = getFeedControls(connectedUser);
}
// filter based on opt-out feed controls (if any)
if (! acceptActivity(activityPost, feedControls))
{
excludedConnections++;
}
else
{
for (String fmTemplate : fmTemplates)
{
// determine format - based on template naming convention
String formatFound = null;
for (String format : formats)
{
if (fmTemplate.contains("."+format+"."))
{
formatFound = format;
break;
}
}
if (formatFound == null)
{
formatFound = defaultFormat;
logger.warn("Unknown format for: " + fmTemplate + " default to '"+formatFound+"'");
}
ActivityFeedDAO feed = new ActivityFeedDAO();
// Generate activity feed summary
feed.setFeedUserId(connectedUser);
feed.setPostUserId(postingUserId);
feed.setActivityType(activityType);
if (formatFound.equals("json"))
{
// allows generic JSON template to simply pass straight through
model.put("activityData", activityPost.getActivityData());
}
String activitySummary = processFreemarker(fmTemplate, cfg, model);
if (! activitySummary.equals(""))
{
feed.setActivitySummary(activitySummary);
feed.setActivitySummaryFormat(formatFound);
feed.setSiteNetwork(activityPost.getSiteNetwork());
feed.setAppTool(activityPost.getAppTool());
feed.setPostDate(activityPost.getPostDate());
feed.setPostId(activityPost.getId());
feed.setFeedDate(new Date());
// Insert activity feed
insertFeedEntry(feed); // ignore returned feedId
totalGenerated++;
}
else
{
if (logger.isDebugEnabled())
{
logger.debug("Empty template result for activityType '" + activityType + "' using format '" + formatFound + "' hence skip feed entry (activity post " + activityPost.getId() + ")");
}
}
}
}
}
updatePostStatus(activityPost.getId(), ActivityPostDAO.STATUS.PROCESSED);
commitTransaction();
if (logger.isDebugEnabled())
{
logger.debug(">>> Processed: " + (connectedUsers.size() - excludedConnections) + " connections for activity post " + activityPost.getId() + " (excluded " + excludedConnections + ")");
}
}
finally
{
endTransaction();
}
}
}
catch(SQLException se)
{
logger.error(se);
throw se;
}
finally
{
logger.info(">>> Generated " + totalGenerated + " activity feed entries for " + (activityPosts == null ? 0 : activityPosts.size()) + " activity posts");
}
}
public abstract void startTransaction() throws SQLException;
public abstract void commitTransaction() throws SQLException;
public abstract void endTransaction() throws SQLException;
public abstract List<ActivityPostDAO> selectPosts(ActivityPostDAO selector) throws SQLException;
public abstract List<FeedControlDAO> selectUserFeedControls(String userId) throws SQLException;
public abstract long insertFeedEntry(ActivityFeedDAO feed) throws SQLException;
public abstract int updatePostStatus(long id, ActivityPostDAO.STATUS status) throws SQLException;
protected String callWebScript(String urlString, String ticket) throws MalformedURLException, URISyntaxException, IOException
{
URL url = new URL(urlString);
if (logger.isDebugEnabled())
{
logger.debug(">>> Request URI: " + url.toURI());
}
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
if (ticket != null)
{
// add Base64 encoded authorization header
// refer to: http://wiki.alfresco.com/wiki/Web_Scripts_Framework#HTTP_Basic_Authentication
conn.addRequestProperty("Authorization", "Basic " + Base64.encodeBytes(ticket.getBytes()));
}
String result = null;
InputStream is = null;
BufferedReader br = null;
try
{
is = conn.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
String line = null;
StringBuffer sb = new StringBuffer();
while(((line = br.readLine()) !=null)) {
sb.append(line);
}
result = sb.toString();
if (logger.isDebugEnabled())
{
int responseCode = conn.getResponseCode();
logger.debug(">>> Response code: " + responseCode);
}
}
finally
{
if (br != null) { br.close(); };
if (is != null) { is.close(); };
}
return result;
}
protected Set<String> getSiteMembers(RepoCtx ctx, String siteId) throws Exception
{
Set<String> members = new HashSet<String>();
if ((siteId != null) && (siteId.length() != 0))
{
StringBuffer sbUrl = new StringBuffer();
sbUrl.append(ctx.getRepoEndPoint()).
append(URL_SERVICE_SITES).append("/").append(siteId).append(URL_MEMBERSHIPS);
String jsonArrayResult = callWebScript(sbUrl.toString(), ctx.getTicket());
if ((jsonArrayResult != null) && (jsonArrayResult.length() != 0))
{
JSONArray ja = new JSONArray(jsonArrayResult);
for (int i = 0; i < ja.length(); i++)
{
JSONObject member = (JSONObject)ja.get(i);
JSONObject person = (JSONObject)member.getJSONObject("person");
members.add(person.getString("userName"));
}
}
}
return members;
}
protected Map<String, List<String>> getActivityTypeTemplates(String repoEndPoint, String ticket, String subPath) throws Exception
{
StringBuffer sbUrl = new StringBuffer();
sbUrl.append(repoEndPoint).append(URL_SERVICE_TEMPLATES).append("?p=").append(subPath).append("*").append("&format=json");
String jsonArrayResult = null;
try
{
jsonArrayResult = callWebScript(sbUrl.toString(), ticket);
}
catch (FileNotFoundException e)
{
return null;
}
List<String> allTemplateNames = new ArrayList<String>(10);
if ((jsonArrayResult != null) && (jsonArrayResult.length() != 0))
{
JSONArray ja = new JSONArray(jsonArrayResult);
for (int i = 0; i < ja.length(); i++)
{
String name = ja.getString(i);
if (! name.contains(" (Working Copy)."))
{
allTemplateNames.add(name);
}
}
}
Map<String, List<String>> activityTemplates = new HashMap<String, List<String>>(10);
for (String template : allTemplateNames)
{
// assume template path = <path>/<base-activityType>.<format>.ftl
// and base-activityType can contain "."
String baseActivityType = template;
int idx1 = baseActivityType.lastIndexOf("/");
if (idx1 != -1)
{
baseActivityType = baseActivityType.substring(idx1+1);
}
int idx2 = baseActivityType.lastIndexOf(".");
if (idx2 != -1)
{
int idx3 = baseActivityType.substring(0, idx2).lastIndexOf(".");
if (idx3 != -1)
{
baseActivityType = baseActivityType.substring(0, idx3);
List<String> activityTypeTemplateList = activityTemplates.get(baseActivityType);
if (activityTypeTemplateList == null)
{
activityTypeTemplateList = new ArrayList<String>(1);
activityTemplates.put(baseActivityType, activityTypeTemplateList);
}
activityTypeTemplateList.add(template);
}
}
}
return activityTemplates;
}
protected Configuration getFreemarkerConfiguration(RepoCtx ctx)
{
Configuration cfg = new Configuration();
cfg.setObjectWrapper(new DefaultObjectWrapper());
// custom template loader
cfg.setTemplateLoader(new TemplateWebScriptLoader(ctx.getRepoEndPoint(), ctx.getTicket()));
// TODO review i18n
cfg.setLocalizedLookup(false);
return cfg;
}
protected String processFreemarker(String fmTemplate, Configuration cfg, Map<String, Object> model) throws IOException, TemplateException, Exception
{
Template myTemplate = cfg.getTemplate(fmTemplate);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Writer out = new OutputStreamWriter(bos);
myTemplate.process(model, out);
out.flush();
return new String(bos.toByteArray());
}
protected List<FeedControlDAO> getFeedControls(String connectedUser) throws SQLException
{
// TODO cache for this run
return selectUserFeedControls(connectedUser);
}
protected boolean acceptActivity(ActivityPostDAO activityPost, List<FeedControlDAO> feedControls)
{
if (feedControls == null)
{
return true;
}
for (FeedControlDAO feedControl : feedControls)
{
if ((feedControl.getSiteNetwork() == null) && (feedControl.getAppTool() != null))
{
if (feedControl.getAppTool().equals(activityPost.getAppTool()))
{
// exclude this appTool (across sites)
return false;
}
}
else if ((feedControl.getAppTool() == null) && (feedControl.getSiteNetwork() != null))
{
if (feedControl.getSiteNetwork().equals(activityPost.getSiteNetwork()))
{
// exclude this site (across appTools)
return false;
}
}
else if ((feedControl.getSiteNetwork() != null) && (feedControl.getAppTool() != null))
{
if ((feedControl.getSiteNetwork().equals(activityPost.getSiteNetwork())) &&
(feedControl.getAppTool().equals(activityPost.getAppTool())))
{
// exclude this appTool for this site
return false;
}
}
}
return true;
}
protected void addMissingFormats(String activityType, List<String> fmTemplates, List<String> templatesToAdd)
{
for (String templateToAdd : templatesToAdd)
{
int idx1 = templateToAdd.lastIndexOf(".");
if (idx1 != -1)
{
int idx2 = templateToAdd.substring(0, idx1).lastIndexOf(".");
if (idx2 != -1)
{
String templateFormat = templateToAdd.substring(idx2+1, idx1);
boolean found = false;
for (String fmTemplate : fmTemplates)
{
if (fmTemplate.contains("."+templateFormat+"."))
{
found = true;
}
}
if (! found)
{
if (logger.isDebugEnabled())
{
logger.debug(">>> Add template '" + templateToAdd + "' for type '" + activityType + "'");
}
fmTemplates.add(templateToAdd);
}
}
}
}
}
protected String getTemplateSubPath(String activityType)
{
return (! activityType.startsWith("/") ? "/" : "") + activityType.replace(".", "/");
}
protected String getBaseActivityType(String activityType)
{
String[] parts = activityType.split("\\.");
return (parts.length != 0 ? parts[parts.length-1] : "");
}
protected class TemplateWebScriptLoader extends URLTemplateLoader
{
private String repoEndPoint;
private String ticketId;
public TemplateWebScriptLoader(String repoEndPoint, String ticketId)
{
this.repoEndPoint = repoEndPoint;
this.ticketId = ticketId;
}
public URL getURL(String templatePath)
{
try
{
StringBuffer sb = new StringBuffer();
sb.append(this.repoEndPoint).
append(URL_SERVICE_TEMPLATE).append("?p=").append(templatePath).
append("&format=text").
append("&alf_ticket=").append(ticketId);
if (logger.isDebugEnabled())
{
logger.debug(">>> getURL: " + sb.toString());
}
return new URL(sb.toString());
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Responsible for splitting the feed task into feed jobs (to be executed locally or on a grid)
*/
public class FeedTaskSplit
{
private static Log logger = LogFactory.getLog(FeedTaskSplit.class);
public Collection<JobSettings> split(int gridSize, JobSettings splitSettings)
{
long maxSequence = splitSettings.getMaxSeq();
if (logger.isDebugEnabled())
{
logger.debug("split: start - gridSize = " + gridSize + ", maxSequence = " + maxSequence);
}
long minSequence = maxSequence - splitSettings.getMaxItemsPerCycle() + 1;
splitSettings.setMinSeq((minSequence >= 0L ? minSequence : 0L));
List<JobSettings> jobs = new ArrayList<JobSettings>(gridSize);
int maxNodeHash = splitSettings.getJobTaskNode();
// note: gridSize may change between runs, hence use maximum node hash/bucket for this cycle
for (int n = 1; n <= maxNodeHash; n++)
{
// every job gets its own copy of the jobSettings (with different nodeHash) as an argument.
JobSettings jobSettings = splitSettings.clone();
jobSettings.setJobTaskNode(n);
jobs.add(jobSettings);
}
return jobs;
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.io.Serializable;
/**
* Job settings passed from grid task to grid job
*/
public class JobSettings implements Serializable
{
public static final long serialVersionUID = -3896042917378679686L;
private int jobTaskNode;
private long maxSeq;
private long minSeq;
private RepoCtx ctx;
private int maxItemsPerCycle;
public int getJobTaskNode()
{
return jobTaskNode;
}
public void setJobTaskNode(int jobTaskNode)
{
this.jobTaskNode = jobTaskNode;
}
public long getMaxSeq()
{
return maxSeq;
}
public void setMaxSeq(long maxSeq)
{
this.maxSeq = maxSeq;
}
public long getMinSeq()
{
return minSeq;
}
public void setMinSeq(long minSeq)
{
this.minSeq = minSeq;
}
public RepoCtx getWebScriptsCtx() {
return ctx;
}
public void setWebScriptsCtx(RepoCtx ctx) {
this.ctx = ctx;
}
public int getMaxItemsPerCycle()
{
return maxItemsPerCycle;
}
public void setMaxItemsPerCycle(int maxItemsPerCycle)
{
this.maxItemsPerCycle = maxItemsPerCycle;
}
public JobSettings clone()
{
JobSettings js = new JobSettings();
js.setMaxItemsPerCycle(this.maxItemsPerCycle);
js.setMaxSeq(this.maxSeq);
js.setMinSeq(this.minSeq);
js.setJobTaskNode(this.jobTaskNode);
js.setWebScriptsCtx(this.ctx); // note: shallow copy
return js;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2005-2008 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.feed;
import java.io.Serializable;
/**
* Repository context passed from grid task to grid job
*/
public class RepoCtx implements Serializable
{
private String repoEndPoint; // http://hostname:port/webapp (eg. http://localhost:8080/alfresco)
private String ticket;
public static final long serialVersionUID = -3896042917378679686L;
public RepoCtx(String repoEndPoint)
{
this.repoEndPoint = repoEndPoint.endsWith("/") ? repoEndPoint.substring(0, repoEndPoint.length()-1) : repoEndPoint;
}
public String getRepoEndPoint() {
return repoEndPoint;
}
public String getTicket()
{
return ticket;
}
public void setTicket(String ticket)
{
this.ticket = ticket;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2008 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.feed.cleanup;
import java.sql.SQLException;
import java.util.Date;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.activities.feed.ActivityFeedDaoService;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.VmShutdownListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionException;
/**
* The feed cleaner component is responsible for purging 'obsolete' activity feed entries
*/
public class FeedCleaner
{
private static Log logger = LogFactory.getLog(FeedCleaner.class);
private static VmShutdownListener vmShutdownListener = new VmShutdownListener(FeedCleaner.class.getName());
private int maxAgeMins = 0;
private ActivityFeedDaoService feedDaoService;
public void setFeedDaoService(ActivityFeedDaoService feedDaoService)
{
this.feedDaoService = feedDaoService;
}
public void setMaxAgeMins(int mins)
{
this.maxAgeMins = mins;
}
/**
* Perform basic checks to ensure that the necessary dependencies were injected.
*/
private void checkProperties()
{
PropertyCheck.mandatory(this, "feedDaoService", feedDaoService);
// check the max age
if (maxAgeMins <= 0)
{
throw new AlfrescoRuntimeException("Property 'maxAgeMins' must be greater than 0");
}
}
public void execute() throws JobExecutionException
{
checkProperties();
try
{
long nowTimeOffset = new Date().getTime();
long keepTimeOffset = nowTimeOffset - (maxAgeMins*60*1000); // millsecs = mins * 60 secs * 1000 msecs
Date keepDate = new Date(keepTimeOffset);
// clean old entries
int deletedCount = feedDaoService.deleteFeedEntries(keepDate);
if (logger.isDebugEnabled())
{
logger.debug("Cleaned " + deletedCount + " entries (upto " + keepDate + ", max age " + maxAgeMins + " mins)");
}
}
catch (SQLException e)
{
logger.error("Exception during cleanup of feeds", e);
throw new JobExecutionException(e);
}
catch (Throwable e)
{
// If the VM is shutting down, then ignore
if (vmShutdownListener.isVmShuttingDown())
{
// Ignore
}
else
{
logger.error("Exception during cleanup of feeds", e);
}
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 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.feed.cleanup;
import org.alfresco.error.AlfrescoRuntimeException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Executes scheduled feed cleaner quartz-job - refer to scheduled-jobs-context.xml
*/
public class FeedCleanupJob implements Job
{
public FeedCleanupJob()
{
}
/**
* Calls the feed cleaner to do its work
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap jobData = context.getJobDetail().getJobDataMap();
// extract the feed cleaner to use
Object feedCleanerObj = jobData.get("feedCleaner");
if (feedCleanerObj == null || !(feedCleanerObj instanceof FeedCleaner))
{
throw new AlfrescoRuntimeException(
"FeedCleanupJob data must contain valid 'feedCleaner' reference");
}
FeedCleaner feedCleaner = (FeedCleaner)feedCleanerObj;
feedCleaner.execute();
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2005-2008 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.feed.control;
import java.util.Date;
import org.alfresco.service.cmr.activities.FeedControl;
/**
* Activity Feed Control DAO
*/
public class FeedControlDAO
{
private long id; // internal DB-generated id
private String feedUserId;
private String siteNetwork;
private String appTool;
private Date lastModified; // when inserted
// TODO - review - deleted feed controls are not kept and available feed controls are currently retrieved during generation, hence
// it is possible for a feed control to be applied even if lastModified is greater than postDate - could check the date !
// it is also possible for a feed control to not be applied if it is deleted just after the post - would need to keep, at least until next generation
public FeedControlDAO()
{
}
public FeedControlDAO(String feedUserId)
{
this.feedUserId = feedUserId;
}
public FeedControlDAO(String feedUserId, FeedControl feedControl)
{
this.feedUserId = feedUserId;
this.siteNetwork = feedControl.getSiteId();
this.appTool = feedControl.getAppToolId();
}
public FeedControl getFeedControl()
{
return new FeedControl(this.siteNetwork, this.appTool);
}
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getSiteNetwork()
{
return siteNetwork;
}
public void setSiteNetwork(String siteNetwork)
{
this.siteNetwork = siteNetwork;
}
public String getAppTool()
{
return appTool;
}
public void setAppTool(String appTool)
{
this.appTool = appTool;
}
public String getFeedUserId()
{
return feedUserId;
}
public void setFeedUserId(String feedUserId)
{
this.feedUserId = feedUserId;
}
public Date getLastModified()
{
return lastModified;
}
public void setLastModified(Date lastModified)
{
this.lastModified = lastModified;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2005-2008 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.feed.control;
import java.sql.SQLException;
import java.util.List;
/**
* Interface for user activity feed controls DAO service
*/
public interface FeedControlDaoService
{
public long insertFeedControl(FeedControlDAO activityFeedControl) throws SQLException;
public int deleteFeedControl(FeedControlDAO activityFeedControl) throws SQLException;
public List<FeedControlDAO> selectFeedControls(String userId) throws SQLException;
public long selectFeedControl(FeedControlDAO activityFeedControl) throws SQLException;
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2005-2008 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.feed.local;
import java.util.Collection;
import java.util.Date;
import org.alfresco.repo.activities.feed.AbstractFeedGenerator;
import org.alfresco.repo.activities.feed.FeedGridJob;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.activities.feed.JobSettings;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The local (ie. not grid) feed generator component is responsible for generating feed entries
*/
public class LocalFeedGenerator extends AbstractFeedGenerator
{
private static Log logger = LogFactory.getLog(LocalFeedGenerator.class);
private FeedTaskProcessor feedTaskProcessor;
public void setFeedTaskProcessor(FeedTaskProcessor feedTaskProcessor)
{
this.feedTaskProcessor = feedTaskProcessor;
}
public int getEstimatedGridSize()
{
return 1;
}
public void init() throws Exception
{
super.init();
}
protected boolean generate() throws Exception
{
Long maxSequence = getPostDaoService().getMaxActivitySeq();
Integer maxNodeHash = getPostDaoService().getMaxNodeHash();
String gridName = "local";
if (maxSequence != null)
{
if (logger.isDebugEnabled())
{
logger.debug(">>> Execute job cycle: " + gridName + " (maxSeq: " + maxSequence + ")");
}
long startTime = new Date().getTime();
// TODO ... or push this upto to job scheduler ... ?
AuthenticationUtil.runAs(new RunAsWork<Object>()
{
public Object doWork()
{
getWebScriptsCtx().setTicket(getAuthenticationService().getCurrentTicket());
return null;
}
}, AuthenticationUtil.getSystemUserName()); // need web scripts to support System-level authentication ... see RepositoryContainer !
JobSettings js = new JobSettings();
js.setMaxSeq(maxSequence);
js.setJobTaskNode(maxNodeHash);
js.setWebScriptsCtx(getWebScriptsCtx());
js.setMaxItemsPerCycle(getMaxItemsPerCycle());
LocalFeedTaskSplitter splitter = new LocalFeedTaskSplitter();
splitter.setFeedTaskProcessor(feedTaskProcessor);
Collection<FeedGridJob> jobs = splitter.split(getEstimatedGridSize(), js);
for (FeedGridJob job : jobs)
{
job.execute();
}
long endTime = new Date().getTime();
if (logger.isDebugEnabled())
{
logger.debug(">>> Finish job cycle: " + gridName + " (time taken (secs) = " + ((endTime - startTime) / 1000) + ")");
}
return true;
}
else
{
if (logger.isDebugEnabled())
{
logger.debug(">>> No work to be done for this job cycle: " + gridName);
}
return false;
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2008 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.feed.local;
import java.io.Serializable;
import org.alfresco.repo.activities.feed.FeedGridJob;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.activities.feed.JobSettings;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Implementation to execute local (ie. not grid) feed job
*/
public class LocalFeedGridJob implements FeedGridJob
{
private static final Log logger = LogFactory.getLog(LocalFeedGridJob.class);
private JobSettings arg;
private FeedTaskProcessor feedTaskProcessor;
public void setFeedTaskProcessor(FeedTaskProcessor feedTaskProcessor)
{
this.feedTaskProcessor = feedTaskProcessor;
}
public Serializable execute() throws Exception
{
JobSettings js = getArgument();
if (logger.isDebugEnabled()) { logger.debug(">>> Execute: nodehash '" + js.getJobTaskNode() + "' from seq '" + js.getMinSeq() + "' to seq '" + js.getMaxSeq() + "' on this node"); }
try
{
feedTaskProcessor.process(js.getJobTaskNode(), js.getMinSeq(), js.getMaxSeq(), js.getWebScriptsCtx());
}
catch (Exception e)
{
logger.error(e);
throw new Exception(e.getMessage(), e.getCause());
}
// This job does not return any result.
return null;
}
public void setArgument(JobSettings arg)
{
this.arg = arg;
}
public JobSettings getArgument()
{
return this.arg;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2005-2008 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.feed.local;
import java.sql.SQLException;
import java.util.List;
import org.alfresco.repo.activities.feed.ActivityFeedDAO;
import org.alfresco.repo.activities.feed.ActivityFeedDaoService;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.activities.feed.control.FeedControlDAO;
import org.alfresco.repo.activities.feed.control.FeedControlDaoService;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
import com.ibatis.sqlmap.client.SqlMapClient;
/**
* The local (ie. not grid) feed task processor is responsible for processing the individual feed job
*/
public class LocalFeedTaskProcessor extends FeedTaskProcessor
{
private ActivityPostDaoService postDaoService;
private ActivityFeedDaoService feedDaoService;
private FeedControlDaoService feedControlDaoService;
// used to start/end/commit transaction
// note: currently assumes that all dao services are configured with this mapper / data source
private SqlMapClient sqlMapper;
public void setPostDaoService(ActivityPostDaoService postDaoService)
{
this.postDaoService = postDaoService;
}
public void setFeedDaoService(ActivityFeedDaoService feedDaoService)
{
this.feedDaoService = feedDaoService;
}
public void setFeedControlDaoService(FeedControlDaoService feedControlDaoService)
{
this.feedControlDaoService = feedControlDaoService;
}
public void setSqlMapClient(SqlMapClient sqlMapper)
{
this.sqlMapper = sqlMapper;
}
public void startTransaction() throws SQLException
{
sqlMapper.startTransaction();
}
public void commitTransaction() throws SQLException
{
sqlMapper.commitTransaction();
}
public void endTransaction() throws SQLException
{
sqlMapper.endTransaction();
}
public List<ActivityPostDAO> selectPosts(ActivityPostDAO selector) throws SQLException
{
return postDaoService.selectPosts(selector);
}
public long insertFeedEntry(ActivityFeedDAO feed) throws SQLException
{
return feedDaoService.insertFeedEntry(feed);
}
public int updatePostStatus(long id, ActivityPostDAO.STATUS status) throws SQLException
{
return postDaoService.updatePostStatus(id, status);
}
public List<FeedControlDAO> selectUserFeedControls(String userId) throws SQLException
{
return feedControlDaoService.selectFeedControls(userId);
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2005-2008 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.feed.local;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.alfresco.repo.activities.feed.FeedGridJob;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.activities.feed.FeedTaskSplit;
import org.alfresco.repo.activities.feed.JobSettings;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* The local feed task splitter is responsible for splitting the feed task into feed jobs
*/
public class LocalFeedTaskSplitter
{
private static final Log logger = LogFactory.getLog(LocalFeedTaskSplitter.class);
private FeedTaskProcessor feedTaskProcessor;
public void setFeedTaskProcessor(FeedTaskProcessor feedTaskProcessor)
{
this.feedTaskProcessor = feedTaskProcessor;
}
public Collection<FeedGridJob> split(int gridSize, Object o) throws Exception
{
try
{
FeedTaskSplit feedSplitter = new FeedTaskSplit();
Collection<JobSettings> jobs = feedSplitter.split(gridSize, (JobSettings)o);
List<FeedGridJob> gridJobs = new ArrayList<FeedGridJob>(jobs.size());
for (JobSettings job : jobs)
{
LocalFeedGridJob gridJob = new LocalFeedGridJob();
gridJob.setFeedTaskProcessor(feedTaskProcessor);
gridJob.setArgument(job);
gridJobs.add(gridJob);
}
return gridJobs;
//return (Collection<FeedGridJob>)feedSplitter.split(gridSize, (JobSettings)o, new LocalFeedGridJob());
}
catch (Exception e)
{
logger.equals(e);
throw new Exception(e.getMessage());
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2005-2008 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.ibatis;
import java.sql.SQLException;
/**
* Common interface for activity DAO service
*/
public interface ActivityDaoService
{
public void startTransaction() throws SQLException;
public void commitTransaction() throws SQLException;
public void endTransaction() throws SQLException;
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2005-2008 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.ibatis;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import org.alfresco.repo.activities.feed.ActivityFeedDAO;
import org.alfresco.repo.activities.feed.ActivityFeedDaoService;
public class IBatisActivityFeedDaoServiceImpl extends IBatisSqlMapper implements ActivityFeedDaoService
{
public long insertFeedEntry(ActivityFeedDAO activityFeed) throws SQLException
{
Long id = (Long)getSqlMapClient().insert("insert.activity.feed", activityFeed);
return (id != null ? id : -1);
}
public int deleteFeedEntries(Date keepDate) throws SQLException
{
return getSqlMapClient().delete("delete.activity.feed.entries.older.than.date", keepDate);
}
@SuppressWarnings("unchecked")
public List<ActivityFeedDAO> selectUserFeedEntries(String feedUserId, String format) throws SQLException
{
ActivityFeedDAO params = new ActivityFeedDAO();
params.setFeedUserId(feedUserId);
params.setActivitySummaryFormat(format);
// where feed user is me and post user is not me
return (List<ActivityFeedDAO>)getSqlMapClient().queryForList("select.activity.feed.for.feeduser", params);
}
@SuppressWarnings("unchecked")
public List<ActivityFeedDAO> selectUserFeedEntries(String feedUserId, String format, String siteId) throws SQLException
{
ActivityFeedDAO params = new ActivityFeedDAO();
params.setFeedUserId(feedUserId);
params.setPostUserId(feedUserId);
params.setActivitySummaryFormat(format);
params.setSiteNetwork(siteId);
// where feed user is me and post user is not me
return (List<ActivityFeedDAO>)getSqlMapClient().queryForList("select.activity.feed.for.feeduser.and.site", params);
}
@SuppressWarnings("unchecked")
public List<ActivityFeedDAO> selectSiteFeedEntries(String siteId, String format) throws SQLException
{
ActivityFeedDAO params = new ActivityFeedDAO();
params.setSiteNetwork(siteId);
params.setActivitySummaryFormat(format);
// where feed user is me and post user is not me
return (List<ActivityFeedDAO>)getSqlMapClient().queryForList("select.activity.feed.for.site", params);
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2005-2008 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.ibatis;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
public class IBatisActivityPostDaoServiceImpl extends IBatisSqlMapper implements ActivityPostDaoService
{
@SuppressWarnings("unchecked")
public List<ActivityPostDAO> selectPosts(ActivityPostDAO activityPost) throws SQLException
{
if ((activityPost.getJobTaskNode() != -1) &&
(activityPost.getMinId() != -1) &&
(activityPost.getMaxId() != -1) &&
(activityPost.getStatus() != null))
{
return (List<ActivityPostDAO>)getSqlMapClient().queryForList("select.activity.posts", activityPost);
}
else if (activityPost.getStatus() != null)
{
return (List<ActivityPostDAO>)getSqlMapClient().queryForList("select.activity.posts.by.status.only", activityPost);
}
else
{
return new ArrayList<ActivityPostDAO>(0);
}
}
public Long getMaxActivitySeq() throws SQLException
{
return (Long)getSqlMapClient().queryForObject("select.activity.post.max.seq");
}
public Long getMinActivitySeq() throws SQLException
{
return (Long)getSqlMapClient().queryForObject("select.activity.post.min.seq");
}
public Integer getMaxNodeHash() throws SQLException
{
return (Integer)getSqlMapClient().queryForObject("select.activity.post.max.jobtasknode");
}
public int updatePost(long id, String siteNetwork, String activityData, ActivityPostDAO.STATUS status) throws SQLException
{
ActivityPostDAO post = new ActivityPostDAO();
post.setId(id);
post.setSiteNetwork(siteNetwork);
post.setActivityData(activityData);
post.setStatus(status.toString());
post.setLastModified(new Date());
return getSqlMapClient().update("update.activity.post.data", post);
}
public int updatePostStatus(long id, ActivityPostDAO.STATUS status) throws SQLException
{
ActivityPostDAO post = new ActivityPostDAO();
post.setId(id);
post.setStatus(status.toString());
post.setLastModified(new Date());
return getSqlMapClient().update("update.activity.post.status", post);
}
public int deletePosts(Date keepDate, ActivityPostDAO.STATUS status) throws SQLException
{
ActivityPostDAO params = new ActivityPostDAO();
params.setPostDate(keepDate);
params.setStatus(status.toString());
return getSqlMapClient().delete("delete.activity.posts.older.than.date", params);
}
public long insertPost(ActivityPostDAO activityPost) throws SQLException
{
Long id = (Long)getSqlMapClient().insert("insert.activity.post", activityPost);
return (id != null ? id : -1);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2005-2008 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.ibatis;
import java.sql.SQLException;
import java.util.List;
import org.alfresco.repo.activities.feed.control.FeedControlDAO;
import org.alfresco.repo.activities.feed.control.FeedControlDaoService;
public class IBatisFeedControlDaoServiceImpl extends IBatisSqlMapper implements FeedControlDaoService
{
public long insertFeedControl(FeedControlDAO activityFeedControl) throws SQLException
{
Long id = (Long)getSqlMapClient().insert("insert.activity.feedcontrol", activityFeedControl);
return (id != null ? id : -1);
}
public int deleteFeedControl(FeedControlDAO activityFeedControl) throws SQLException
{
return getSqlMapClient().delete("delete.activity.feedcontrol", activityFeedControl);
}
@SuppressWarnings("unchecked")
public List<FeedControlDAO> selectFeedControls(String feedUserId) throws SQLException
{
FeedControlDAO params = new FeedControlDAO(feedUserId);
return (List<FeedControlDAO>)getSqlMapClient().queryForList("select.activity.feedcontrols.for.user", params);
}
public long selectFeedControl(FeedControlDAO activityFeedControl) throws SQLException
{
Long id = (Long)getSqlMapClient().queryForObject("select.activity.feedcontrol", activityFeedControl);
return (id != null ? id : -1);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2005-2008 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.ibatis;
import java.sql.SQLException;
import com.ibatis.sqlmap.client.SqlMapClient;
public class IBatisSqlMapper implements ActivityDaoService
{
private SqlMapClient sqlMapper;
public void setSqlMapClient(SqlMapClient sqlMapper)
{
this.sqlMapper = sqlMapper;
}
public SqlMapClient getSqlMapClient()
{
return this.sqlMapper;
}
public void startTransaction() throws SQLException
{
sqlMapper.startTransaction();
}
public void commitTransaction() throws SQLException
{
sqlMapper.commitTransaction();
}
public void endTransaction() throws SQLException
{
sqlMapper.endTransaction();
}
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2005-2008 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.post;
import java.util.Date;
/**
* Activity Post DAO
*/
public class ActivityPostDAO
{
public enum STATUS { POSTED, PENDING, PROCESSED, ERROR };
private long id; // internal DB-generated sequence id
private String activityData;
private String activityType;
private String userId;
private int jobTaskNode = -1;
private String siteNetwork;
private String appTool;
private String status;
private Date postDate;
private Date lastModified; // for debug
// for selector
private long minId = -1;
private long maxId = -1;
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getUserId()
{
return userId;
}
public void setUserId(String userId)
{
this.userId = userId;
}
public int getJobTaskNode()
{
return jobTaskNode;
}
public void setJobTaskNode(int jobTaskNode)
{
this.jobTaskNode = jobTaskNode;
}
public long getMinId()
{
return minId;
}
public void setMinId(long minId)
{
this.minId = minId;
}
public long getMaxId()
{
return maxId;
}
public void setMaxId(long maxId)
{
this.maxId = maxId;
}
public String getSiteNetwork()
{
return siteNetwork;
}
public void setSiteNetwork(String siteNetwork)
{
this.siteNetwork = siteNetwork;
}
public String getActivityData()
{
return activityData;
}
public void setActivityData(String activityData)
{
this.activityData = activityData;
}
public String getActivityType()
{
return activityType;
}
public void setActivityType(String activityType)
{
this.activityType = activityType;
}
public Date getPostDate()
{
return postDate;
}
public void setPostDate(Date postDate)
{
this.postDate = postDate;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public Date getLastModified()
{
return lastModified;
}
public void setLastModified(Date lastModified)
{
this.lastModified = lastModified;
}
public String getAppTool()
{
return appTool;
}
public void setAppTool(String appTool)
{
this.appTool = appTool;
}
// for debug only
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("ActivityPost\n[");
sb.append("id=").append(id).append(",");
sb.append("status=").append(status).append(",");
sb.append("postDate=").append(postDate).append(",");
sb.append("userId=").append(userId).append(",");
sb.append("siteNetwork=").append(siteNetwork).append(",");
sb.append("appTool=").append(appTool).append(",");
sb.append("type=").append(activityType).append(",");
sb.append("jobTaskNode=").append(jobTaskNode).append(",");
sb.append("data=\n").append(activityData).append("\n]");
return sb.toString();
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2005-2008 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.post;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import org.alfresco.repo.activities.ibatis.ActivityDaoService;
/**
* Interface for activity post DAO service
*/
public interface ActivityPostDaoService extends ActivityDaoService
{
public List<ActivityPostDAO> selectPosts(ActivityPostDAO activityPost) throws SQLException;
public Long getMaxActivitySeq() throws SQLException;
public Long getMinActivitySeq() throws SQLException;
public Integer getMaxNodeHash() throws SQLException;
public int deletePosts(Date keepDate, ActivityPostDAO.STATUS status) throws SQLException;
public long insertPost(ActivityPostDAO activityPost) throws SQLException;
public int updatePost(long id, String network, String activityData, ActivityPostDAO.STATUS status) throws SQLException;
public int updatePostStatus(long id, ActivityPostDAO.STATUS status) throws SQLException;
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2008 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.post.cleanup;
import java.sql.SQLException;
import java.util.Date;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.VmShutdownListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionException;
/**
* Thr post cleaner component is responsible for purging 'obsolete' activity posts
*/
public class PostCleaner
{
private static Log logger = LogFactory.getLog(PostCleaner.class);
private static VmShutdownListener vmShutdownListener = new VmShutdownListener(PostCleaner.class.getName());
private int maxAgeMins = 0;
private ActivityPostDaoService postDaoService;
public void setPostDaoService(ActivityPostDaoService postDaoService)
{
this.postDaoService = postDaoService;
}
public void setMaxAgeMins(int mins)
{
this.maxAgeMins = mins;
}
/**
* Perform basic checks to ensure that the necessary dependencies were injected.
*/
private void checkProperties()
{
PropertyCheck.mandatory(this, "postDaoService", postDaoService);
// check the max age
if (maxAgeMins <= 0)
{
throw new AlfrescoRuntimeException("Property 'maxAgeMins' must be greater than 0");
}
}
public void execute() throws JobExecutionException
{
checkProperties();
try
{
long nowTimeOffset = new Date().getTime();
long keepTimeOffset = nowTimeOffset - (maxAgeMins*60*1000); // millsecs = mins * 60 secs * 1000 msecs
Date keepDate = new Date(keepTimeOffset);
// clean old entries - PROCESSED - does not clean POSTED or PENDING, which will need to be done manually, if stuck
int deletedCount = postDaoService.deletePosts(keepDate, ActivityPostDAO.STATUS.PROCESSED);
if (logger.isDebugEnabled())
{
logger.debug("Cleaned " + deletedCount + " entries (upto " + keepDate + ", max age " + maxAgeMins + " mins)");
}
}
catch (SQLException e)
{
logger.error("Exception during cleanup of posts", e);
throw new JobExecutionException(e);
}
catch (Throwable e)
{
// If the VM is shutting down, then ignore
if (vmShutdownListener.isVmShuttingDown())
{
// Ignore
}
else
{
logger.error("Exception during cleanup of posts", e);
}
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 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.post.cleanup;
import org.alfresco.error.AlfrescoRuntimeException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Executes scheduled post cleaner quartz-job - refer to scheduled-jobs-context.xml
*/
public class PostCleanupJob implements Job
{
public PostCleanupJob()
{
}
/**
* Calls the post cleaner to do its work
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap jobData = context.getJobDetail().getJobDataMap();
// extract the post cleaner to use
Object postCleanerObj = jobData.get("postCleaner");
if (postCleanerObj == null || !(postCleanerObj instanceof PostCleaner))
{
throw new AlfrescoRuntimeException(
"FeedCleanupJob data must contain valid 'postCleaner' reference");
}
PostCleaner postCleaner = (PostCleaner)postCleanerObj;
postCleaner.execute();
}
}

View File

@@ -0,0 +1,292 @@
/*
* Copyright (C) 2005-2008 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.post.lookup;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.activities.post.ActivityPostDAO;
import org.alfresco.repo.activities.post.ActivityPostDaoService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.JSONtoFmModel;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.VmShutdownListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONStringer;
import org.quartz.JobExecutionException;
/**
* The post lookup component is responsible for updating posts that require a secondary lookup (to get additional activity data)
*/
public class PostLookup
{
private static Log logger = LogFactory.getLog(PostLookup.class);
private static VmShutdownListener vmShutdownListener = new VmShutdownListener(PostLookup.class.getName());
private ActivityPostDaoService postDaoService;
private NodeService nodeService;
private PermissionService permissionService;
private TransactionService transactionService;
private PersonService personService;
public void setPostDaoService(ActivityPostDaoService postDaoService)
{
this.postDaoService = postDaoService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
/**
* Perform basic checks to ensure that the necessary dependencies were injected.
*/
private void checkProperties()
{
PropertyCheck.mandatory(this, "postDaoService", postDaoService);
PropertyCheck.mandatory(this, "nodeService", nodeService);
PropertyCheck.mandatory(this, "permissionService", permissionService);
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "personService", personService);
}
public void execute() throws JobExecutionException
{
checkProperties();
try
{
ActivityPostDAO params = new ActivityPostDAO();
params.setStatus(ActivityPostDAO.STATUS.PENDING.toString());
List<ActivityPostDAO> activityPosts = postDaoService.selectPosts(params);
if (activityPosts.size() > 0)
{
logger.info("Update: " + activityPosts.size() + " activity posts");
}
for (ActivityPostDAO activityPost : activityPosts)
{
Map<String, Object> model = JSONtoFmModel.convertJSONObjectToMap(activityPost.getActivityData());
String postUserId = activityPost.getUserId();
String name = (String)model.get("name"); // can be null
String nodeRefStr = (String)model.get("nodeRef"); // required
NodeRef nodeRef = new NodeRef(nodeRefStr);
String parentNodeRefStr = (String)model.get("parentNodeRef"); // optional
NodeRef parentNodeRef = null;
if (parentNodeRefStr != null)
{
parentNodeRef = new NodeRef(parentNodeRefStr);
}
String typeQName = (String)model.get("typeQName");
try
{
postDaoService.startTransaction();
Pair<String, String> siteNetworkActivityData = lookup(activityPost.getSiteNetwork(), nodeRef, name, typeQName, parentNodeRef, postUserId);
activityPost.setSiteNetwork(siteNetworkActivityData.getFirst());
activityPost.setActivityData(siteNetworkActivityData.getSecond());
activityPost.setLastModified(new Date());
postDaoService.updatePost(activityPost.getId(), activityPost.getSiteNetwork(), activityPost.getActivityData(), ActivityPostDAO.STATUS.POSTED);
if (logger.isDebugEnabled())
{
activityPost.setStatus(ActivityPostDAO.STATUS.POSTED.toString()); // for debug output
logger.debug("Updated: " + activityPost);
}
postDaoService.commitTransaction();
}
catch (JSONException e)
{
// log error, but consume exception (skip this post)
logger.error(e);
}
catch (SQLException e)
{
logger.error("Exception during update of post", e);
throw new JobExecutionException(e);
}
finally
{
postDaoService.endTransaction();
}
}
}
catch (SQLException e)
{
logger.error("Exception during select of posts", e);
throw new JobExecutionException(e);
}
catch (Throwable e)
{
// If the VM is shutting down, then ignore
if (vmShutdownListener.isVmShuttingDown())
{
// Ignore
}
else
{
logger.error("Exception during update of posts", e);
}
}
}
private Pair<String, String> lookup(final String networkIn, final NodeRef nodeRef, final String nameIn, final String typeQNameIn, final NodeRef parentNodeRef, final String postUserId) throws JSONException
{
return AuthenticationUtil.runAs(new RunAsWork<Pair<String, String>>()
{
public Pair<String, String> doWork() throws Exception
{
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
// wrap to make the request in a transaction
RetryingTransactionCallback<Pair<String, String>> lookup = new RetryingTransactionCallback<Pair<String, String>>()
{
public Pair<String, String> execute() throws Throwable
{
String jsonString = null;
String displayPath = "";
String name = nameIn;
String network = networkIn;
String typeQName = typeQNameIn;
Path path = null;
String firstName = "";
String lastName = "";
if (personService.personExists(postUserId))
{
NodeRef personRef = personService.getPerson(postUserId);
firstName = (String)nodeService.getProperty(personRef, ContentModel.PROP_FIRSTNAME);
lastName = (String)nodeService.getProperty(personRef, ContentModel.PROP_LASTNAME);
}
if (((name == null) || (name.length() == 0)) && (nodeRef != null) && (nodeService.exists(nodeRef)))
{
// node exists, lookup node name
if ((name == null) || (name.length() == 0))
{
name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
}
path = nodeService.getPath(nodeRef);
// TODO: missing the prefix ?
typeQName = nodeService.getType(nodeRef).toPrefixString();
}
if (((path == null) || (path.size() == 0)) && (parentNodeRef != null) && (nodeService.exists(parentNodeRef)))
{
// parent node exists, lookup parent node path
path = nodeService.getPath(parentNodeRef);
}
if (path != null)
{
// lookup display path
displayPath = path.toDisplayPath(nodeService, permissionService);
// note: for now, also tack on the node name
displayPath += "/" + name;
}
if (name == null)
{
name = "";
}
if (typeQName == null)
{
typeQName = "";
}
// activity data
jsonString = new JSONStringer()
.object()
.key("name")
.value(name)
.key("nodeRef")
.value(nodeRef)
.key("typeQName")
.value(typeQName)
.key("displayPath")
.value(displayPath)
.key("firstName")
.value(firstName)
.key("lastName")
.value(lastName)
.endObject().toString();
return new Pair<String, String>(network, jsonString);
}
};
// execute in txn
return txnHelper.doInTransaction(lookup, true);
}
}, AuthenticationUtil.getSystemUserName());
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2005-2008 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.post.lookup;
import org.alfresco.error.AlfrescoRuntimeException;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* Executes scheduled post lookup quartz-job - refer to scheduled-jobs-context.xml
*/
public class PostLookupJob implements Job
{
public PostLookupJob()
{
}
/**
* Calls the post lookup to do its work
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobDataMap jobData = context.getJobDetail().getJobDataMap();
// extract the post cleaner to use
Object postLookupObj = jobData.get("postLookup");
if (postLookupObj == null || !(postLookupObj instanceof PostLookup))
{
throw new AlfrescoRuntimeException(
"FeedCleanupJob data must contain valid 'postLookup' reference");
}
PostLookup postLookup = (PostLookup)postLookupObj;
postLookup.execute();
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2007 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.script;
import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.service.cmr.activities.ActivityService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Scripted Activity Service for posting activities.
*/
public final class Activity extends BaseScopableProcessorExtension
{
private ActivityService activityService;
/**
* Set the activity service
*
* @param activityService the activity service
*/
public void setActivityService(ActivityService activityService)
{
this.activityService = activityService;
}
/**
* 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)
{
activityService.postActivity(activityType, siteId, appTool, jsonActivityData);
}
/**
* Post a pre-defined activity type - activity data will be looked-up asynchronously, including:
*
* name
* 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)
{
activityService.postActivity(activityType, siteId, appTool, 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)
{
activityService.postActivity(activityType, siteId, appTool, nodeRef, 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)
{
activityService.postActivity(activityType, siteId, appTool, nodeRef, name, typeQName, parentNodeRef);
}
}

View File

@@ -0,0 +1,19 @@
// called by ActivityServiceImplTest.java (test_JSAPI)
var failure = "did not complete script";
// invalid
// activities.postActivity("my activity type", null, null, null);
// activities.postActivity(null, "my site", "my app tool", '{ 000 }');
// valid
activities.postActivity("test activity type 4", null, null, '{ "item1" : 123 }');
activities.postActivity("test activity type 5", "my site", null, '{ "item2" : 456 }');
activities.postActivity("test activity type 6", "my site", "my app tool", '{ "item3" : 789 }');
activities.postActivity("test activity type 7", "my site", "my app tool", '{ invalidJSON }');
failure = "";
// Return the failure message
failure;

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2005-2008 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 java.util.List;
import java.util.Map;
import org.alfresco.service.cmr.repository.NodeRef;
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 user feed
*
* @param userId - required
* @param format - required
* @param siteId - optional, if set then will filter by given siteId else return all sites
*/
public List<Map<String, Object>> getUserFeedEntries(String userId, String format, String siteId);
/**
* Retrieve site feed
*
* @param activityType - required
* @param format - required
*/
public List<Map<String, Object>> getSiteFeedEntries(String siteId, String format);
/*
* Manage User Feed Controls
*/
/**
* For current user, set feed control (opt-out) for a site or an appTool or a site/appTool
*
* @param feedControl - required
*/
public void setFeedControl(FeedControl feedControl);
/**
* For given user, get feed controls
*
* @param userId - required (must match
* @return list of user feed controls
*/
public List<FeedControl> getFeedControls(String userId);
/**
* For current user, get feed controls
*
* @return list of user feed controls
*/
public List<FeedControl> getFeedControls();
/**
* For current user, unset feed control
*
* @param feedControl - required
*/
public void unsetFeedControl(FeedControl feedControl);
/**
* For current user, does the feed control exist ?
*
* @param feedControl - required
* @return true, if user feed control exists
*/
public boolean existsFeedControl(FeedControl feedControl);
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2005-2008 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;
public class FeedControl
{
private String siteId;
private String appToolId;
public FeedControl(String siteId, String appToolId)
{
if (siteId == null) siteId = "";
this.siteId = siteId;
if (appToolId == null) appToolId = "";
this.appToolId = appToolId;
}
public String getSiteId()
{
return this.siteId;
}
public String getAppToolId()
{
return this.appToolId;
}
}

View File

@@ -95,6 +95,10 @@ public abstract class BaseSpringTest extends AbstractTransactionalDataSourceSpri
{
// The derived class is using the default context
defaultContext = true;
this.setAutowireMode(AUTOWIRE_BY_NAME);
//this.setDependencyCheck(false);
if (logger.isDebugEnabled())
{
logger.debug("Getting config locations");