mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2E to HEAD
17571: ETHREEOH-1863 - alfresco-webscript-framework.jar is not available in the alfresco-enterprise-sdk-3.1 - although the framework jar was already part of the SDK when I looked I have done some re-organising of - names and paths and added missing source files. By no means finished but its another step forward. 17581: Fix for ETHREEOH-3380 - upload servlet in Explorer does not handle well upload errors as no error message is displayed on the client browser. 17582: ETHREEOH-2760 - Sealing of standard library root scope objects to prevent script potentially interfering with another scripts processing. - Example provided to fix ACT ticket issue against fixed codeline. 17583: Fixed ETHREEOH-3458 "If the rss feed to display returns bad formatted data or is unavailable an ugly free marker error is displayed" - Rss urls pointing to a "missing resource"/"bad formated rss data" is now displayed as "Rss feed is unavailable"/"Can't read rss feed" (before they displayed freemarker error making it impossible to re-configure) - Title is now updated after config (therefore the change to return json instead of html) (before a page refresh was needed) - The new url is now updated in the "2nd" config dialog after it has been changed in the first (before page refresh was needed) - Removed un-internationalised string from config respons template 17584: ALFCOM-3675 - WebDAV script does not allow inline editing for documents with name in upper case. - Now allows any case, as per supplied patch. - Also added support for Office 2007 file types so they can now be opened in write mode via webdav in IE6/7 from the Explorer client. - Tested in IE6/7. 17585: Yet another fix for ETHREEOH-1733 - agenda view all days events fixed 17586: ETHREEOH-1843: /api/sites/*/memberships search is slow on specific query 17587: Add cluster lock for JPBM job/timer executor (for WCM submits in a clustered env - ETHREEOH-2230 / ETHREEOH-3319) 17590: New icons for View Original & View Working Copy actions 17591: ETHREEOH-2879 - Alfresco + OpenLDAP: Unable to retrieve user from repository. - Fixed SURF to handle users without (utterly bizarely) First or Last names or even, usefully, neither. 17592: Merged V3.2 to V3.1 17415: Fix for ETHREEOH-3293 - Editing user details on large user repository causes Hibernate exception. Fix for ETHREEOH-3294 - Extreemly slow repository performance adding a new user to large user repository via the Explorer Client admin console. 17593: Icon for doclib View In Browser action 17594: ETHREEOH-2864 - Share - Documents cannot be deleted (in "All Documents" view) 17595: ETHREEOH-3203: Impossibility to add comment to any object by SiteContributor user 17596: ETHREEOH-1469 - SMTP errors not reported when sending an invitation - now errors are reported. - may upset unit tests, i've fixed those I know about 17598: Fixed ETHREEOH-3445 "Admin Console - Group Search sometimes never displays results list" 17601: ETHREEOH-3382 - Share Sites menu is broken in "debug" mode. Reworked menu css. Removed unused footer component. 17602: Share global debug flags removed from web-framework-config-application.xml. Use share-config-custom.xml instead. 17603: Changed wording on Create/Edit Site dialogs from "Access" to "Visibility". "Access" was no longer accurate now that Moderated Sites' content is private to non-members. 17604: ETHREEOH-1469 - SMTP error when sending an invitation does not return a failure. - SiteServiceTest also needed "fixing" 17606: ETHREEOH-3475 - IE: Second search on add groups to site gets yui error but works. Related to YUI bug 2286608. YUI patched instead of all DataTable client code. (Patch removed from DocLib) 17607: ETHREEOH-3470 - "Add" button is unavailable if the group with the name of more than 60 characters is found 17608: Fixed invalid use of Forms validator. Validators updated to handle specific case anyway. 17610: Fixed ETHREEOH-3445 "Admin Console - Group Search sometimes never displays results list" - missed commit of non-default theme files 17612: Fixed ETHREEOH-3480 "Browse" button no longer works after Groups Admin console page is refreshed 17613: ETHREEOH-3450 Fixed illegal nested comment in web-client-config-custom.xml.sample 17616: Fix for ETHREEOH-2863 - Code cache memory leak observed in JVM 1.6 when script action calls another script which in turn calls other functions. - Fixed use of Rhino optimization level when executing string based scripts. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18160 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -35,6 +35,7 @@ import java.util.Set;
|
|||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||||
import org.alfresco.repo.template.DateCompareMethod;
|
import org.alfresco.repo.template.DateCompareMethod;
|
||||||
@@ -56,6 +57,7 @@ import org.apache.commons.logging.Log;
|
|||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.commons.validator.EmailValidator;
|
import org.apache.commons.validator.EmailValidator;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.mail.MailException;
|
||||||
import org.springframework.mail.javamail.JavaMailSender;
|
import org.springframework.mail.javamail.JavaMailSender;
|
||||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||||
import org.springframework.mail.javamail.MimeMessagePreparator;
|
import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||||
@@ -138,6 +140,15 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
|
|||||||
*/
|
*/
|
||||||
private String repoRemoteUrl = null;
|
private String repoRemoteUrl = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test mode prevents email messages from being sent.
|
||||||
|
* It is used when unit testing when we don't actually want to send out email messages.
|
||||||
|
*
|
||||||
|
* MER 20/11/2009 This is a quick and dirty fix. It should be replaced by being
|
||||||
|
* "mocked out" or some other better way of running the unit tests.
|
||||||
|
*/
|
||||||
|
private boolean testMode = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param javaMailSender the java mail sender
|
* @param javaMailSender the java mail sender
|
||||||
*/
|
*/
|
||||||
@@ -236,7 +247,9 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the rule action
|
* Send an email message
|
||||||
|
*
|
||||||
|
* @throws AlfrescoRuntimeExeption
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void executeImpl(
|
protected void executeImpl(
|
||||||
@@ -378,12 +391,14 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Send the message
|
// Send the message unless we are in "testMode"
|
||||||
|
if(!testMode)
|
||||||
|
{
|
||||||
javaMailSender.send(mailPreparer);
|
javaMailSender.send(mailPreparer);
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
}
|
||||||
|
catch (MailException e)
|
||||||
{
|
{
|
||||||
// don't stop the action but let admins know email is not getting sent
|
|
||||||
String to = (String)ruleAction.getParameterValue(PARAM_TO);
|
String to = (String)ruleAction.getParameterValue(PARAM_TO);
|
||||||
if (to == null)
|
if (to == null)
|
||||||
{
|
{
|
||||||
@@ -395,6 +410,8 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Failed to send email to " + to, e);
|
logger.error("Failed to send email to " + to, e);
|
||||||
|
|
||||||
|
throw new AlfrescoRuntimeException("Failed to send email to:" + to, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +478,16 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
|
|||||||
paramList.add(new ParameterDefinitionImpl(PARAM_TEMPLATE, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_TEMPLATE)));
|
paramList.add(new ParameterDefinitionImpl(PARAM_TEMPLATE, DataTypeDefinition.NODE_REF, false, getParamDisplayLabel(PARAM_TEMPLATE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTestMode(boolean testMode)
|
||||||
|
{
|
||||||
|
this.testMode = testMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTestMode()
|
||||||
|
{
|
||||||
|
return testMode;
|
||||||
|
}
|
||||||
|
|
||||||
public static class URLHelper
|
public static class URLHelper
|
||||||
{
|
{
|
||||||
String contextPath;
|
String contextPath;
|
||||||
|
@@ -28,6 +28,7 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
|
import org.alfresco.repo.action.executer.MailActionExecuter;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||||
import org.alfresco.repo.site.SiteModel;
|
import org.alfresco.repo.site.SiteModel;
|
||||||
import org.alfresco.service.cmr.invitation.Invitation;
|
import org.alfresco.service.cmr.invitation.Invitation;
|
||||||
@@ -78,11 +79,17 @@ public class InvitationServiceImplTest extends BaseAlfrescoSpringTest
|
|||||||
protected void onSetUpInTransaction() throws Exception
|
protected void onSetUpInTransaction() throws Exception
|
||||||
{
|
{
|
||||||
super.onSetUpInTransaction();
|
super.onSetUpInTransaction();
|
||||||
|
|
||||||
this.invitationService = (InvitationService) this.applicationContext.getBean("InvitationService");
|
this.invitationService = (InvitationService) this.applicationContext.getBean("InvitationService");
|
||||||
this.siteService = (SiteService) this.applicationContext.getBean("SiteService");
|
this.siteService = (SiteService) this.applicationContext.getBean("SiteService");
|
||||||
this.personService = (PersonService) this.applicationContext.getBean("PersonService");
|
this.personService = (PersonService) this.applicationContext.getBean("PersonService");
|
||||||
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent");
|
||||||
|
|
||||||
|
// TODO MER 20/11/2009 Bodge - turn off email sending to prevent errors during unit testing
|
||||||
|
// (or sending out email by accident from tests)
|
||||||
|
MailActionExecuter mail = (MailActionExecuter)this.applicationContext.getBean("mail");
|
||||||
|
mail.setTestMode(true);
|
||||||
|
|
||||||
createPerson(USER_MANAGER, USER_MANAGER + "@alfrescotesting.com", PERSON_FIRSTNAME, PERSON_LASTNAME);
|
createPerson(USER_MANAGER, USER_MANAGER + "@alfrescotesting.com", PERSON_FIRSTNAME, PERSON_LASTNAME);
|
||||||
createPerson(USER_ONE, USER_ONE_EMAIL,USER_ONE_FIRSTNAME, USER_ONE_LASTNAME);
|
createPerson(USER_ONE, USER_ONE_EMAIL,USER_ONE_FIRSTNAME, USER_ONE_LASTNAME);
|
||||||
createPerson(USER_TWO, USER_TWO + "@alfrescotesting.com", PERSON_FIRSTNAME, PERSON_LASTNAME);
|
createPerson(USER_TWO, USER_TWO + "@alfrescotesting.com", PERSON_FIRSTNAME, PERSON_LASTNAME);
|
||||||
|
@@ -404,7 +404,6 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
|||||||
model = convertToRhinoModel(model);
|
model = convertToRhinoModel(model);
|
||||||
|
|
||||||
Context cx = Context.enter();
|
Context cx = Context.enter();
|
||||||
cx.setOptimizationLevel(1);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create a thread-specific scope from one of the shared scopes.
|
// Create a thread-specific scope from one of the shared scopes.
|
||||||
@@ -542,7 +541,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
cx.setWrapFactory(wrapFactory);
|
cx.setWrapFactory(wrapFactory);
|
||||||
this.secureScope = cx.initStandardObjects();
|
this.secureScope = cx.initStandardObjects(null, true);
|
||||||
|
|
||||||
// remove security issue related objects - this ensures the script may not access
|
// remove security issue related objects - this ensures the script may not access
|
||||||
// unsecure java.* libraries or import any other classes for direct access - only
|
// unsecure java.* libraries or import any other classes for direct access - only
|
||||||
@@ -564,7 +563,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
|||||||
|
|
||||||
// allow access to all libraries and objects, including the importer
|
// allow access to all libraries and objects, including the importer
|
||||||
// @see http://www.mozilla.org/rhino/ScriptingJava.html
|
// @see http://www.mozilla.org/rhino/ScriptingJava.html
|
||||||
this.nonSecureScope = new ImporterTopLevel(cx);
|
this.nonSecureScope = new ImporterTopLevel(cx, true);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@@ -39,6 +39,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
import org.alfresco.model.ContentModel;
|
import org.alfresco.model.ContentModel;
|
||||||
import org.alfresco.repo.activities.ActivityType;
|
import org.alfresco.repo.activities.ActivityType;
|
||||||
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||||
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
|
import org.alfresco.repo.search.impl.lucene.LuceneQueryParser;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationContext;
|
import org.alfresco.repo.security.authentication.AuthenticationContext;
|
||||||
@@ -60,6 +61,8 @@ import org.alfresco.service.cmr.repository.NodeService;
|
|||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.search.QueryParameterDefinition;
|
import org.alfresco.service.cmr.search.QueryParameterDefinition;
|
||||||
import org.alfresco.service.cmr.search.ResultSet;
|
import org.alfresco.service.cmr.search.ResultSet;
|
||||||
|
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||||
|
import org.alfresco.service.cmr.search.SearchParameters;
|
||||||
import org.alfresco.service.cmr.search.SearchService;
|
import org.alfresco.service.cmr.search.SearchService;
|
||||||
import org.alfresco.service.cmr.security.AccessPermission;
|
import org.alfresco.service.cmr.security.AccessPermission;
|
||||||
import org.alfresco.service.cmr.security.AccessStatus;
|
import org.alfresco.service.cmr.security.AccessStatus;
|
||||||
@@ -1145,10 +1148,21 @@ public class SiteServiceImpl implements SiteService, SiteModel
|
|||||||
{
|
{
|
||||||
boolean addUser = false;
|
boolean addUser = false;
|
||||||
|
|
||||||
NodeRef personRef = this.personService.getPerson(username);
|
String query = "+TYPE:\"cm:person\" +@cm\\:userName:\"" + username + "\"";
|
||||||
Map<QName, Serializable> props = this.nodeService.getProperties(personRef);
|
SearchParameters searchParameters = new SearchParameters();
|
||||||
String firstName = (String)props.get(ContentModel.PROP_FIRSTNAME);
|
searchParameters.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||||
String lastName = (String)props.get(ContentModel.PROP_LASTNAME);
|
searchParameters.addStore(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||||
|
searchParameters.setQuery(query);
|
||||||
|
ResultSet resultSet = this.searchService.query(searchParameters);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (resultSet.length() != 0)
|
||||||
|
{
|
||||||
|
ResultSetRow row = resultSet.getRow(0);
|
||||||
|
Map<String, Serializable> values = row.getValues();
|
||||||
|
String firstName = (String)values.get(ContentModel.PROP_FIRSTNAME.toString());
|
||||||
|
String lastName = (String)values.get(ContentModel.PROP_LASTNAME.toString());
|
||||||
|
|
||||||
final String lowFirstName = (firstName != null ? firstName.toLowerCase() : "");
|
final String lowFirstName = (firstName != null ? firstName.toLowerCase() : "");
|
||||||
final String lowLastName = (lastName != null ? lastName.toLowerCase() : "");
|
final String lowLastName = (lastName != null ? lastName.toLowerCase() : "");
|
||||||
for (int i=0; i<nameFilters.length; i++)
|
for (int i=0; i<nameFilters.length; i++)
|
||||||
@@ -1164,6 +1178,12 @@ public class SiteServiceImpl implements SiteService, SiteModel
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
resultSet.close();
|
||||||
|
}
|
||||||
|
|
||||||
return addUser;
|
return addUser;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.workflow.jbpm;
|
package org.alfresco.repo.workflow.jbpm;
|
||||||
|
|
||||||
|
import org.alfresco.repo.lock.JobLockService;
|
||||||
import org.alfresco.service.ServiceRegistry;
|
import org.alfresco.service.ServiceRegistry;
|
||||||
import org.alfresco.service.transaction.TransactionService;
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -46,18 +47,27 @@ public class AlfrescoJobExecutor extends JobExecutor
|
|||||||
|
|
||||||
private static Log log = LogFactory.getLog(JobExecutor.class);
|
private static Log log = LogFactory.getLog(JobExecutor.class);
|
||||||
private TransactionService transactionService;
|
private TransactionService transactionService;
|
||||||
|
|
||||||
private JbpmConfiguration jbpmConfiguration;
|
private JbpmConfiguration jbpmConfiguration;
|
||||||
|
|
||||||
|
private JobLockService jobLockService;
|
||||||
|
private boolean jobExecutorLockEnabled = true;
|
||||||
|
|
||||||
|
public void setJobExecutorLockEnabled(boolean jobExecutorLockEnabled)
|
||||||
|
{
|
||||||
|
this.jobExecutorLockEnabled = jobExecutorLockEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Is Alfresco Job Executor Lock Enabled
|
||||||
|
*
|
||||||
|
* @return true if only one executor thread allowed (including across cluster)
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public AlfrescoJobExecutor()
|
public boolean getJobExecutorLockEnabled()
|
||||||
{
|
{
|
||||||
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
|
return this.jobExecutorLockEnabled;
|
||||||
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
|
|
||||||
transactionService = (TransactionService)factory.getFactory().getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
|
|
||||||
jbpmConfiguration = (JbpmConfiguration)factory.getFactory().getBean("jbpm_configuration");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,6 +80,33 @@ public class AlfrescoJobExecutor extends JobExecutor
|
|||||||
return transactionService;
|
return transactionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Job Lock Service
|
||||||
|
*
|
||||||
|
* @return job lock service
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public JobLockService getJobLockService()
|
||||||
|
{
|
||||||
|
return jobLockService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public AlfrescoJobExecutor()
|
||||||
|
{
|
||||||
|
BeanFactoryLocator factoryLocator = new JbpmFactoryLocator();
|
||||||
|
BeanFactoryReference factory = factoryLocator.useBeanFactory(null);
|
||||||
|
|
||||||
|
transactionService = (TransactionService)factory.getFactory().getBean(ServiceRegistry.TRANSACTION_SERVICE.getLocalName());
|
||||||
|
jobLockService = (JobLockService)factory.getFactory().getBean(ServiceRegistry.JOB_LOCK_SERVICE.getLocalName());
|
||||||
|
|
||||||
|
jbpmConfiguration = (JbpmConfiguration)factory.getFactory().getBean("jbpm_configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.jbpm.job.executor.JobExecutor#startThread()
|
* @see org.jbpm.job.executor.JobExecutor#startThread()
|
||||||
*/
|
*/
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -28,8 +28,13 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.alfresco.repo.lock.LockAcquisitionException;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.jbpm.JbpmConfiguration;
|
import org.jbpm.JbpmConfiguration;
|
||||||
import org.jbpm.job.Job;
|
import org.jbpm.job.Job;
|
||||||
import org.jbpm.job.executor.JobExecutorThread;
|
import org.jbpm.job.executor.JobExecutorThread;
|
||||||
@@ -38,13 +43,24 @@ import org.jbpm.job.executor.JobExecutorThread;
|
|||||||
/**
|
/**
|
||||||
* Alfresco Job Executor Thread
|
* Alfresco Job Executor Thread
|
||||||
*
|
*
|
||||||
* @author davidc
|
* @author davidc, janv
|
||||||
*/
|
*/
|
||||||
public class AlfrescoJobExecutorThread extends JobExecutorThread
|
public class AlfrescoJobExecutorThread extends JobExecutorThread
|
||||||
{
|
{
|
||||||
|
/** The name of the lock used to ensure that job executor does not run on more than one node at the same time. */
|
||||||
|
private static final QName LOCK_QNAME = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI,
|
||||||
|
"AlfrescoJbpmJobExecutor");
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(AlfrescoJobExecutorThread.class);
|
||||||
|
|
||||||
private AlfrescoJobExecutor alfrescoJobExecutor;
|
private AlfrescoJobExecutor alfrescoJobExecutor;
|
||||||
private boolean isActive = true;
|
private boolean isActive = true;
|
||||||
|
|
||||||
|
private long jbpmMaxLockTime;
|
||||||
|
|
||||||
|
private long jobLockTTL = 0;
|
||||||
|
private String jobLockToken = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setActive(boolean isActive)
|
public void setActive(boolean isActive)
|
||||||
{
|
{
|
||||||
@@ -58,26 +74,75 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
|
|||||||
{
|
{
|
||||||
super(name, jobExecutor, jbpmConfiguration, idleInterval, maxIdleInterval, maxLockTime, maxHistory);
|
super(name, jobExecutor, jbpmConfiguration, idleInterval, maxIdleInterval, maxLockTime, maxHistory);
|
||||||
this.alfrescoJobExecutor = jobExecutor;
|
this.alfrescoJobExecutor = jobExecutor;
|
||||||
|
this.jbpmMaxLockTime = maxLockTime;
|
||||||
|
|
||||||
|
this.jobLockTTL = jbpmMaxLockTime+(1000 * 60 * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
protected Collection acquireJobs()
|
protected Collection acquireJobs()
|
||||||
{
|
{
|
||||||
if (!isActive)
|
Collection jobs = Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
if ((isActive) && (! alfrescoJobExecutor.getTransactionService().isReadOnly()))
|
||||||
{
|
{
|
||||||
return Collections.EMPTY_LIST;
|
try
|
||||||
}
|
|
||||||
else if (alfrescoJobExecutor.getTransactionService().isReadOnly())
|
|
||||||
{
|
{
|
||||||
return Collections.EMPTY_LIST;
|
jobs = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
|
||||||
}
|
|
||||||
return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
|
|
||||||
new RetryingTransactionHelper.RetryingTransactionCallback<Collection>() {
|
new RetryingTransactionHelper.RetryingTransactionCallback<Collection>() {
|
||||||
public Collection execute() throws Throwable
|
public Collection execute() throws Throwable
|
||||||
|
{
|
||||||
|
if (jobLockToken != null)
|
||||||
|
{
|
||||||
|
refreshExecutorLock(jobLockToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jobLockToken = getExecutorLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return AlfrescoJobExecutorThread.super.acquireJobs();
|
return AlfrescoJobExecutorThread.super.acquireJobs();
|
||||||
}
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
logger.error("Failed to acquire jobs");
|
||||||
|
releaseExecutorLock(jobLockToken);
|
||||||
|
jobLockToken = null;
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (jobs != null)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled() && (! logger.isTraceEnabled()) && (! jobs.isEmpty()))
|
||||||
|
{
|
||||||
|
logger.debug("acquired "+jobs.size()+" job"+((jobs.size() != 1) ? "s" : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace("acquired "+jobs.size()+" job"+((jobs.size() != 1) ? "s" : "")+((jobs.size() > 0) ? ": "+jobs.toString() : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobs.size() == 0)
|
||||||
|
{
|
||||||
|
releaseExecutorLock(jobLockToken);
|
||||||
|
jobLockToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LockAcquisitionException e)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
jobLockToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -87,6 +152,7 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
|
return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(
|
||||||
new RetryingTransactionHelper.RetryingTransactionCallback<Date>() {
|
new RetryingTransactionHelper.RetryingTransactionCallback<Date>() {
|
||||||
public Date execute() throws Throwable
|
public Date execute() throws Throwable
|
||||||
@@ -102,17 +168,97 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
|
|||||||
@Override
|
@Override
|
||||||
protected void executeJob(Job job)
|
protected void executeJob(Job job)
|
||||||
{
|
{
|
||||||
if (!isActive)
|
if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (alfrescoJobExecutor.getTransactionService().isReadOnly())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(new TransactionJob(job));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(new TransactionJob(job));
|
||||||
|
}
|
||||||
|
catch (LockAcquisitionException e)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
jobLockToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getExecutorLock()
|
||||||
|
{
|
||||||
|
String jobLockToken = null;
|
||||||
|
|
||||||
|
if (alfrescoJobExecutor.getJobExecutorLockEnabled())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
jobLockToken = alfrescoJobExecutor.getJobLockService().getLock(LOCK_QNAME, jobLockTTL, 3000, 10);
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace(Thread.currentThread().getName()+" got lock token: "+jobLockToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LockAcquisitionException e)
|
||||||
|
{
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace("Failed to get Alfresco Job Executor lock - may already running in another thread");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobLockToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshExecutorLock(String jobLockToken)
|
||||||
|
{
|
||||||
|
if (jobLockToken != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
alfrescoJobExecutor.getJobLockService().refreshLock(jobLockToken, LOCK_QNAME, jobLockTTL);
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace(Thread.currentThread().getName()+" refreshed lock token: "+jobLockToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LockAcquisitionException e)
|
||||||
|
{
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace("Failed to refresh Alfresco Job Executor lock - may no longer exist ("+jobLockToken+")");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseExecutorLock(String jobLockToken)
|
||||||
|
{
|
||||||
|
if (jobLockToken != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
alfrescoJobExecutor.getJobLockService().releaseLock(jobLockToken, LOCK_QNAME);
|
||||||
|
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace(Thread.currentThread().getName()+" released lock token: "+jobLockToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (LockAcquisitionException e)
|
||||||
|
{
|
||||||
|
if (logger.isTraceEnabled())
|
||||||
|
{
|
||||||
|
logger.trace("Failed to release Alfresco Job Executor lock - may no longer exist ("+jobLockToken+")");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for holding Job reference
|
* Helper class for holding Job reference
|
||||||
@@ -135,10 +281,16 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread
|
|||||||
|
|
||||||
public Object execute() throws Throwable
|
public Object execute() throws Throwable
|
||||||
{
|
{
|
||||||
|
refreshExecutorLock(jobLockToken);
|
||||||
|
|
||||||
AlfrescoJobExecutorThread.super.executeJob(job);
|
AlfrescoJobExecutorThread.super.executeJob(job);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("executed job: "+job);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user