diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java index ad77d0b13b..82a01ea2a8 100644 --- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java @@ -35,6 +35,7 @@ import java.util.Set; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ParameterDefinitionImpl; 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.validator.EmailValidator; import org.springframework.beans.factory.InitializingBean; +import org.springframework.mail.MailException; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.mail.javamail.MimeMessagePreparator; @@ -80,7 +82,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase public static final String PARAM_TEXT = "text"; public static final String PARAM_FROM = "from"; public static final String PARAM_TEMPLATE = "template"; - + /** * From address */ @@ -138,6 +140,15 @@ public class MailActionExecuter extends ActionExecuterAbstractBase */ 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 */ @@ -236,7 +247,9 @@ public class MailActionExecuter extends ActionExecuterAbstractBase } /** - * Execute the rule action + * Send an email message + * + * @throws AlfrescoRuntimeExeption */ @Override protected void executeImpl( @@ -375,15 +388,17 @@ public class MailActionExecuter extends ActionExecuterAbstractBase } } }; - + try { - // Send the message - javaMailSender.send(mailPreparer); + // Send the message unless we are in "testMode" + if(!testMode) + { + 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); if (to == null) { @@ -395,6 +410,8 @@ public class MailActionExecuter extends ActionExecuterAbstractBase } 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))); } + public void setTestMode(boolean testMode) + { + this.testMode = testMode; + } + + public boolean isTestMode() + { + return testMode; + } + public static class URLHelper { String contextPath; diff --git a/source/java/org/alfresco/repo/invitation/InvitationServiceImplTest.java b/source/java/org/alfresco/repo/invitation/InvitationServiceImplTest.java index dd5cf9d34f..0e35deb0f4 100644 --- a/source/java/org/alfresco/repo/invitation/InvitationServiceImplTest.java +++ b/source/java/org/alfresco/repo/invitation/InvitationServiceImplTest.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.List; import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.executer.MailActionExecuter; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.site.SiteModel; import org.alfresco.service.cmr.invitation.Invitation; @@ -78,11 +79,17 @@ public class InvitationServiceImplTest extends BaseAlfrescoSpringTest protected void onSetUpInTransaction() throws Exception { super.onSetUpInTransaction(); - this.invitationService = (InvitationService)this.applicationContext.getBean("InvitationService"); - this.siteService = (SiteService)this.applicationContext.getBean("SiteService"); - this.personService = (PersonService)this.applicationContext.getBean("PersonService"); + + this.invitationService = (InvitationService) this.applicationContext.getBean("InvitationService"); + this.siteService = (SiteService) this.applicationContext.getBean("SiteService"); + this.personService = (PersonService) this.applicationContext.getBean("PersonService"); 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_ONE, USER_ONE_EMAIL,USER_ONE_FIRSTNAME, USER_ONE_LASTNAME); createPerson(USER_TWO, USER_TWO + "@alfrescotesting.com", PERSON_FIRSTNAME, PERSON_LASTNAME); diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java index edd3f6eeec..c73ec95760 100644 --- a/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java +++ b/source/java/org/alfresco/repo/jscript/RhinoScriptProcessor.java @@ -404,7 +404,6 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess model = convertToRhinoModel(model); Context cx = Context.enter(); - cx.setOptimizationLevel(1); try { // Create a thread-specific scope from one of the shared scopes. @@ -542,7 +541,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess try { 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 // unsecure java.* libraries or import any other classes for direct access - only @@ -555,7 +554,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess { Context.exit(); } - + // Initialise the non-secure scope cx = Context.enter(); try @@ -564,7 +563,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess // allow access to all libraries and objects, including the importer // @see http://www.mozilla.org/rhino/ScriptingJava.html - this.nonSecureScope = new ImporterTopLevel(cx); + this.nonSecureScope = new ImporterTopLevel(cx, true); } finally { diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index 689463f973..59cb52ad3b 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -39,6 +39,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.activities.ActivityType; +import org.alfresco.repo.model.Repository; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; 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.search.QueryParameterDefinition; 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.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; @@ -1145,25 +1148,42 @@ public class SiteServiceImpl implements SiteService, SiteModel { boolean addUser = false; - NodeRef personRef = this.personService.getPerson(username); - Map props = this.nodeService.getProperties(personRef); - String firstName = (String)props.get(ContentModel.PROP_FIRSTNAME); - String lastName = (String)props.get(ContentModel.PROP_LASTNAME); - final String lowFirstName = (firstName != null ? firstName.toLowerCase() : ""); - final String lowLastName = (lastName != null ? lastName.toLowerCase() : ""); - for (int i=0; i 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 lowLastName = (lastName != null ? lastName.toLowerCase() : ""); + for (int i=0; i() { - public Collection execute() throws Throwable + try + { + jobs = alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionHelper.RetryingTransactionCallback() { + public Collection execute() throws Throwable + { + if (jobLockToken != null) + { + refreshExecutorLock(jobLockToken); + } + else + { + jobLockToken = getExecutorLock(); + } + + try + { + return AlfrescoJobExecutorThread.super.acquireJobs(); + } + catch (Throwable t) + { + logger.error("Failed to acquire jobs"); + releaseExecutorLock(jobLockToken); + jobLockToken = null; + throw t; + } + } + }); + + if (jobs != null) { - return AlfrescoJobExecutorThread.super.acquireJobs(); + 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 @@ -87,6 +152,7 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread { return null; } + return alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction( new RetryingTransactionHelper.RetryingTransactionCallback() { public Date execute() throws Throwable @@ -95,24 +161,104 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread } }, true); } - + /** * {@inheritDoc} */ @Override protected void executeJob(Job job) { - if (!isActive) + if ((!isActive) || (alfrescoJobExecutor.getTransactionService().isReadOnly())) { return; } - else if (alfrescoJobExecutor.getTransactionService().isReadOnly()) + + try { - return; + alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(new TransactionJob(job)); + } + catch (LockAcquisitionException e) + { + // ignore + jobLockToken = null; } - alfrescoJobExecutor.getTransactionService().getRetryingTransactionHelper().doInTransaction(new TransactionJob(job)); } + 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 @@ -122,7 +268,7 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread private class TransactionJob implements RetryingTransactionCallback { private Job job; - + /** * Constructor * @@ -132,13 +278,19 @@ public class AlfrescoJobExecutorThread extends JobExecutorThread { this.job = job; } - + public Object execute() throws Throwable { + refreshExecutorLock(jobLockToken); + AlfrescoJobExecutorThread.super.executeJob(job); + + if (logger.isDebugEnabled()) + { + logger.debug("executed job: "+job); + } + return null; } - } - }