diff --git a/config/alfresco/extension/ehcache-custom.xml.sample.cluster b/config/alfresco/extension/ehcache-custom.xml.sample.cluster
index c593c77fba..e78ec63bc0 100644
--- a/config/alfresco/extension/ehcache-custom.xml.sample.cluster
+++ b/config/alfresco/extension/ehcache-custom.xml.sample.cluster
@@ -725,7 +725,7 @@
diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties
index 178ac98842..72b4c83706 100644
--- a/config/alfresco/repository.properties
+++ b/config/alfresco/repository.properties
@@ -243,12 +243,12 @@ fts.indexer.batchSize=1000
# Index cache sizes
#
lucene.indexer.cacheEnabled=true
-lucene.indexer.maxDocIdCacheSize=10000
+lucene.indexer.maxDocIdCacheSize=100000
lucene.indexer.maxDocumentCacheSize=100
lucene.indexer.maxIsCategoryCacheSize=-1
lucene.indexer.maxLinkAspectCacheSize=10000
-lucene.indexer.maxParentCacheSize=10000
-lucene.indexer.maxPathCacheSize=10000
+lucene.indexer.maxParentCacheSize=100000
+lucene.indexer.maxPathCacheSize=100000
lucene.indexer.maxTypeCacheSize=10000
#
# Properties for merge (not this does not affect the final index segment which will be optimised)
diff --git a/source/java/org/alfresco/email/server/EmailServiceImpl.java b/source/java/org/alfresco/email/server/EmailServiceImpl.java
index 9b177f537b..77e48aeef1 100644
--- a/source/java/org/alfresco/email/server/EmailServiceImpl.java
+++ b/source/java/org/alfresco/email/server/EmailServiceImpl.java
@@ -42,6 +42,8 @@ import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
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.springframework.extensions.surf.util.ParameterCheck;
/**
@@ -65,6 +67,14 @@ public class EmailServiceImpl implements EmailService
private SearchService searchService;
private RetryingTransactionHelper retryingTransactionHelper;
private AuthorityService authorityService;
+
+ /**
+ * The authority that needs to contain the users and groups
+ * who are allowed to contribute email.
+ */
+ private String emailContributorsAuthority="EMAIL_CONTRIBUTORS";
+
+ private static Log logger = LogFactory.getLog(EmailServiceImpl.class);
private boolean emailInboundEnabled;
/** Login of user that is set as unknown. */
@@ -337,10 +347,19 @@ public class EmailServiceImpl implements EmailService
{
if (unknownUser == null || unknownUser.length() == 0)
{
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("unable to find user for from: " + from);
+ }
throw new EmailMessageException(ERR_UNKNOWN_SOURCE_ADDRESS, from);
}
else
{
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("unable to find user for from - return anonymous: " + from);
+ }
+
userName = unknownUser;
}
}
@@ -375,13 +394,24 @@ public class EmailServiceImpl implements EmailService
/**
* Check that the user is the member in EMAIL_CONTRIBUTORS group
*
- * @param userName User name
+ * @param userName Alfresco user name
* @return True if the user is member of the group
* @exception EmailMessageException Exception will be thrown if the EMAIL_CONTRIBUTORS group isn't found
*/
private boolean isEmailContributeUser(String userName)
{
return this.authorityService.getAuthoritiesForUser(userName).contains(
- authorityService.getName(AuthorityType.GROUP, "EMAIL_CONTRIBUTORS"));
+ authorityService.getName(AuthorityType.GROUP, getEmailContributorsAuthority()));
+ }
+
+ public void setEmailContributorsAuthority(
+ String emailContributorsAuthority)
+ {
+ this.emailContributorsAuthority = emailContributorsAuthority;
+ }
+
+ public String getEmailContributorsAuthority()
+ {
+ return emailContributorsAuthority;
}
}
diff --git a/source/java/org/alfresco/email/server/EmailServiceImplTest.java b/source/java/org/alfresco/email/server/EmailServiceImplTest.java
index 39ef252d9c..1fccc9709f 100644
--- a/source/java/org/alfresco/email/server/EmailServiceImplTest.java
+++ b/source/java/org/alfresco/email/server/EmailServiceImplTest.java
@@ -18,52 +18,36 @@
*/
package org.alfresco.email.server;
-import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.HashMap;
import java.util.Properties;
import java.util.Set;
-import java.io.Serializable;
-import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
+
+import junit.framework.TestCase;
import org.alfresco.email.server.impl.subetha.SubethaEmailMessage;
import org.alfresco.model.ContentModel;
-import org.alfresco.repo.imap.ImapServiceImpl;
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
-import org.alfresco.repo.security.person.PersonServiceImpl;
-import org.alfresco.service.ServiceRegistry;
-import org.alfresco.service.cmr.admin.AdminService;
-import org.alfresco.service.cmr.coci.CheckOutCheckInService;
-import org.alfresco.service.cmr.email.EmailMessage;
import org.alfresco.service.cmr.email.EmailMessageException;
import org.alfresco.service.cmr.email.EmailService;
-import org.alfresco.service.cmr.lock.LockService;
-import org.alfresco.service.cmr.repository.ContentService;
-import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AuthorityService;
-import org.alfresco.service.cmr.security.MutableAuthenticationService;
-import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
-import org.alfresco.service.cmr.version.VersionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
-import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
-import org.alfresco.util.BaseSpringTest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.filters.StringInputStream;
@@ -71,8 +55,6 @@ import org.springframework.context.ApplicationContext;
import com.sun.mail.smtp.SMTPMessage;
-import junit.framework.TestCase;
-
/**
* Unit test of EmailServiceImplTest
* @author mrogers
@@ -205,7 +187,7 @@ public class EmailServiceImplTest extends TestCase
InputStream is = new StringInputStream(bos.toString());
assertNotNull("is is null", is);
- SubethaEmailMessage m = new SubethaEmailMessage(from, to, is);
+ SubethaEmailMessage m = new SubethaEmailMessage(is);
emailService.importMessage(m);
fail("anonymous user not rejected");
@@ -221,6 +203,9 @@ public class EmailServiceImplTest extends TestCase
*
* Send From the test user TEST_EMAIL to the test user's home
*/
+ {
+ logger.debug("Step 2");
+
String from = TEST_EMAIL;
String to = testUserHomeDBID;
String content = "hello world";
@@ -241,10 +226,85 @@ public class EmailServiceImplTest extends TestCase
InputStream is = new StringInputStream(bos.toString());
assertNotNull("is is null", is);
- SubethaEmailMessage m = new SubethaEmailMessage(from, to, is);
+ SubethaEmailMessage m = new SubethaEmailMessage(is);
emailService.importMessage(m);
}
+
+ /**
+ * Step 3
+ *
+ * From with < name@ domain > format
+ *
+ * Send From the test user to the test user's home
+ */
+ {
+ logger.debug("Step 3");
+
+ String from = " \"Joe Bloggs\" <" + TEST_EMAIL + ">";
+ String to = testUserHomeDBID;
+ String content = "hello world";
+
+ Session sess = Session.getDefaultInstance(new Properties());
+ assertNotNull("sess is null", sess);
+ SMTPMessage msg = new SMTPMessage(sess);
+ InternetAddress[] toa = { new InternetAddress(to) };
+
+ msg.setFrom(new InternetAddress(from));
+ msg.setRecipients(Message.RecipientType.TO, toa);
+ msg.setSubject("JavaMail APIs transport.java Test");
+ msg.setContent(content, "text/plain");
+
+ StringBuffer sb = new StringBuffer();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ msg.writeTo(System.out);
+ msg.writeTo(bos);
+ InputStream is = new StringInputStream(bos.toString());
+ assertNotNull("is is null", is);
+
+ SubethaEmailMessage m = new SubethaEmailMessage(is);
+
+ emailService.importMessage(m);
+ }
+
+// /**
+// * Step 4
+// *
+// * From with format
+// *
+// * RFC3696
+// *
+// * Send From the test user to the test user's home
+// */
+// {
+// logger.debug("Step 4 format");
+//
+// String from = "\"Joe Bloggs\" ";
+// String to = testUserHomeDBID;
+// String content = "hello world";
+//
+// Session sess = Session.getDefaultInstance(new Properties());
+// assertNotNull("sess is null", sess);
+// SMTPMessage msg = new SMTPMessage(sess);
+// InternetAddress[] toa = { new InternetAddress(to) };
+//
+// msg.setFrom(new InternetAddress(from));
+// msg.setRecipients(Message.RecipientType.TO, toa);
+// msg.setSubject("JavaMail APIs transport.java Test");
+// msg.setContent(content, "text/plain");
+//
+// StringBuffer sb = new StringBuffer();
+// ByteArrayOutputStream bos = new ByteArrayOutputStream();
+// msg.writeTo(System.out);
+// msg.writeTo(bos);
+// InputStream is = new StringInputStream(bos.toString());
+// assertNotNull("is is null", is);
+//
+// SubethaEmailMessage m = new SubethaEmailMessage(is);
+//
+// emailService.importMessage(m);
+// }
+ }
/**
@@ -313,7 +373,7 @@ public class EmailServiceImplTest extends TestCase
InputStream is = new StringInputStream(bos.toString());
assertNotNull("is is null", is);
- SubethaEmailMessage m = new SubethaEmailMessage(from, to, is);
+ SubethaEmailMessage m = new SubethaEmailMessage(is);
emailService.importMessage(m);
diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java
index dc66d19101..5571ba54d8 100644
--- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java
+++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java
@@ -101,11 +101,8 @@ public class SubethaEmailMessage implements EmailMessage
processMimeMessage(mimeMessage);
}
- public SubethaEmailMessage(String from, String to, InputStream dataInputStream)
+ public SubethaEmailMessage(InputStream dataInputStream)
{
- this.to = to;
- this.from = from;
-
MimeMessage mimeMessage = null;
try
{
@@ -136,8 +133,16 @@ public class SubethaEmailMessage implements EmailMessage
{
throw new EmailMessageException(ERR_NO_FROM_ADDRESS);
}
+ if(addresses[0] instanceof InternetAddress)
+ {
+ from = ((InternetAddress)addresses[0]).getAddress();
+ }
+ else
+ {
from = addresses[0].toString();
}
+
+ }
if (to == null)
{
@@ -154,6 +159,15 @@ public class SubethaEmailMessage implements EmailMessage
{
throw new EmailMessageException(ERR_NO_TO_ADDRESS);
}
+ if(addresses[0] instanceof InternetAddress)
+ {
+ to = ((InternetAddress)addresses[0]).getAddress();
+ }
+ else
+ {
+ to = addresses[0].toString();
+ }
+
to = addresses[0].toString();
}
diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java
index 8ce2ca15ae..792e05aada 100644
--- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java
+++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java
@@ -24,6 +24,9 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+
import org.alfresco.email.server.EmailServer;
import org.alfresco.service.cmr.email.EmailMessage;
import org.alfresco.service.cmr.email.EmailMessageException;
@@ -41,7 +44,7 @@ import org.subethamail.smtp.server.SMTPServer;
*/
public class SubethaEmailServer extends EmailServer
{
- private final static Log log = LogFactory.getLog(SubethaEmailServer.class);
+ private final static Log logger = LogFactory.getLog(SubethaEmailServer.class);
private SMTPServer serverImpl;
@@ -91,7 +94,6 @@ public class SubethaEmailServer extends EmailServer
private List EMPTY_LIST = new LinkedList();
- private String from;
private MessageContext messageContext;
List deliveries = new ArrayList();
@@ -105,11 +107,25 @@ public class SubethaEmailServer extends EmailServer
return messageContext;
}
- public void from(String from) throws RejectException
+ public void from(String fromString) throws RejectException
{
- this.from = from;
+ String from = fromString;
+
try
{
+ InternetAddress a = new InternetAddress(from);
+ from = a.getAddress();
+ }
+ catch (AddressException e)
+ {
+ }
+
+ try
+ {
+ if(logger.isDebugEnabled())
+ {
+ logger.debug("check whether user is allowed to send email from" + from);
+ }
filterSender(from);
}
catch (EmailMessageException e)
@@ -187,7 +203,7 @@ public class SubethaEmailServer extends EmailServer
EmailMessage emailMessage;
try
{
- emailMessage = new SubethaEmailMessage(from, delivery.getRecipient(), data);
+ emailMessage = new SubethaEmailMessage(data);
getEmailService().importMessage(emailMessage);
}
catch (EmailMessageException e)
diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
index 2cc261b4ac..655f3f2509 100644
--- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
+++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java
@@ -36,6 +36,8 @@ import org.alfresco.repo.template.DateCompareMethod;
import org.alfresco.repo.template.HasAspectMethod;
import org.alfresco.repo.template.I18NMessageMethod;
import org.alfresco.repo.template.TemplateNode;
+import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
+import org.alfresco.repo.transaction.TransactionListenerAdapter;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ParameterDefinition;
@@ -81,6 +83,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
public static final String PARAM_TEMPLATE = "template";
public static final String PARAM_TEMPLATE_MODEL = "template_model";
public static final String PARAM_IGNORE_SEND_FAILURE = "ignore_send_failure";
+ public static final String PARAM_SEND_AFTER_COMMIT = "send_after_commit";
/**
* From address
@@ -297,6 +300,31 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
protected void executeImpl(
final Action ruleAction,
final NodeRef actionedUponNodeRef)
+ {
+ if (sendAfterCommit(ruleAction))
+ {
+ AlfrescoTransactionSupport.bindListener(new TransactionListenerAdapter()
+ {
+ @Override
+ public void afterCommit()
+ {
+ prepareAndSendEmail(ruleAction, actionedUponNodeRef);
+ }
+ });
+ }
+ else
+ {
+ prepareAndSendEmail(ruleAction, actionedUponNodeRef);
+ }
+ }
+
+ private boolean sendAfterCommit(Action action)
+ {
+ Boolean sendAfterCommit = (Boolean) action.getParameterValue(PARAM_SEND_AFTER_COMMIT);
+ return sendAfterCommit == null ? false : sendAfterCommit.booleanValue();
+ }
+
+ private void prepareAndSendEmail(final Action ruleAction, final NodeRef actionedUponNodeRef)
{
// Create the mime mail message
MimeMessagePreparator mailPreparer = new MimeMessagePreparator()
@@ -546,6 +574,7 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
}
}
+
/**
* Return true if address has valid format
* @param address
@@ -658,6 +687,15 @@ public class MailActionExecuter extends ActionExecuterAbstractBase
{
return lastTestMessage;
}
+
+ /**
+ * Used when test mode is enabled.
+ * Clears the record of the last message that was sent.
+ */
+ public void clearLastTestMessage()
+ {
+ lastTestMessage = null;
+ }
public static class URLHelper
{
diff --git a/source/java/org/alfresco/repo/preference/PreferenceServiceImpl.java b/source/java/org/alfresco/repo/preference/PreferenceServiceImpl.java
index 640396505d..12d194f6eb 100644
--- a/source/java/org/alfresco/repo/preference/PreferenceServiceImpl.java
+++ b/source/java/org/alfresco/repo/preference/PreferenceServiceImpl.java
@@ -28,7 +28,6 @@ import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
-import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.security.authentication.AuthenticationContext;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
@@ -256,12 +255,6 @@ public class PreferenceServiceImpl implements PreferenceService
contentWriter.setEncoding("UTF-8");
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
contentWriter.putContent(jsonPrefs.toString());
-
- // Lets stop rule inheritance from trying to kick in - we may be in many groups
- if (!PreferenceServiceImpl.this.nodeService.hasAspect(personNodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES))
- {
- PreferenceServiceImpl.this.nodeService.addAspect(personNodeRef, RuleModel.ASPECT_IGNORE_INHERITED_RULES, null);
- }
}
catch (JSONException exception)
{
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
index 61775cb7f6..e340e8ef71 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
@@ -19,6 +19,7 @@
package org.alfresco.repo.rule;
import java.io.File;
+import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -27,6 +28,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
@@ -57,6 +60,8 @@ import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.dictionary.M2Aspect;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Property;
+import org.alfresco.repo.management.subsystems.ApplicationContextFactory;
+import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
@@ -898,11 +903,11 @@ public class RuleServiceCoverageTest extends TestCase
* Test:
* rule type: inbound
* condition: no-condition
- * action: mail
- *
- * Note: this test will be removed from the standard list since it is not currently automated
+ * action: mail
+ * @throws MessagingException
+ * @throws IOException
*/
- public void xtestMailAction()
+ public void testMailAction() throws MessagingException, IOException
{
this.nodeService.addAspect(this.nodeRef, ContentModel.ASPECT_LOCKABLE, null);
@@ -919,6 +924,11 @@ public class RuleServiceCoverageTest extends TestCase
null);
this.ruleService.saveRule(this.nodeRef, rule);
+
+ MailActionExecuter mailService = (MailActionExecuter) ((ApplicationContextFactory) this.applicationContext
+ .getBean("OutboundSMTP")).getApplicationContext().getBean("mail");
+ mailService.setTestMode(true);
+ mailService.clearLastTestMessage();
this.nodeService.createNode(
this.nodeRef,
@@ -928,8 +938,63 @@ public class RuleServiceCoverageTest extends TestCase
getContentProperties()).getChildRef();
// An email should appear in the recipients email
-
// System.out.println(NodeStoreInspector.dumpNodeStore(this.nodeService, this.testStoreRef));
+ MimeMessage lastMessage = mailService.retrieveLastTestMessage();
+ assertNotNull("Message should have been sent", lastMessage);
+ System.out.println("Sent email with subject: " + lastMessage.getSubject());
+ System.out.println("Sent email with content: " + lastMessage.getContent());
+ }
+
+ public void testMailNotSentIfRollback()
+ {
+ this.nodeService.addAspect(this.nodeRef, ContentModel.ASPECT_LOCKABLE, null);
+
+ Map params = new HashMap(1);
+ params.put(MailActionExecuter.PARAM_TO, "alfresco.test@gmail.com");
+ params.put(MailActionExecuter.PARAM_SUBJECT, "testMailNotSentIfRollback()");
+ params.put(MailActionExecuter.PARAM_TEXT, "This email should NOT have been sent.");
+
+ Rule rule = createRule(
+ RuleType.INBOUND,
+ MailActionExecuter.NAME,
+ params,
+ NoConditionEvaluator.NAME,
+ null);
+
+ this.ruleService.saveRule(this.nodeRef, rule);
+
+ String illegalName = "MyName.txt "; // space at end
+
+ MailActionExecuter mailService = (MailActionExecuter) ((ApplicationContextFactory) this.applicationContext
+ .getBean("OutboundSMTP")).getApplicationContext().getBean("mail");
+ mailService.setTestMode(true);
+ mailService.clearLastTestMessage();
+
+ try
+ {
+ this.nodeService.createNode(
+ this.nodeRef,
+ ContentModel.ASSOC_CHILDREN,
+ QName.createQName(TEST_NAMESPACE, "children"),
+ ContentModel.TYPE_CONTENT,
+ makeNameProperty(illegalName)).getChildRef();
+ fail("createNode() should have failed.");
+ }
+ catch(IntegrityException e)
+ {
+ // Expected exception.
+ // An email should NOT appear in the recipients email
+ }
+
+ MimeMessage lastMessage = mailService.retrieveLastTestMessage();
+ assertNull("Message should NOT have been sent", lastMessage);
+ }
+
+ private Map makeNameProperty(String name)
+ {
+ Map properties = new HashMap(1);
+ properties.put(ContentModel.PROP_NAME, name);
+ return properties;
}
/**
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
index 505885659b..18b1c14c79 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java
@@ -30,6 +30,8 @@ import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionModel;
import org.alfresco.repo.action.RuntimeActionService;
+import org.alfresco.repo.action.executer.CompositeActionExecuter;
+import org.alfresco.repo.action.executer.MailActionExecuter;
import org.alfresco.repo.cache.NullCache;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.repo.node.NodeServicePolicies;
@@ -41,6 +43,7 @@ import org.alfresco.repo.transaction.TransactionListener;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ActionServiceException;
+import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.CopyService;
@@ -86,6 +89,13 @@ public class RuleServiceImpl
private String ASSOC_NAME_RULES_PREFIX = "rules";
private RegexQNamePattern ASSOC_NAME_RULES_REGEX = new RegexQNamePattern(RuleModel.RULE_MODEL_URI, "^" + ASSOC_NAME_RULES_PREFIX + ".*");
+ private static final Set IGNORE_PARENT_ASSOC_TYPES = new HashSet(7);
+ static
+ {
+ IGNORE_PARENT_ASSOC_TYPES.add(ContentModel.ASSOC_MEMBER);
+ IGNORE_PARENT_ASSOC_TYPES.add(ContentModel.ASSOC_IN_ZONE);
+ }
+
private static Log logger = LogFactory.getLog(RuleServiceImpl.class);
private NodeService nodeService;
@@ -611,6 +621,12 @@ public class RuleServiceImpl
List parents = this.runtimeNodeService.getParentAssocs(nodeRef);
for (ChildAssociationRef parent : parents)
{
+ // We are not interested in following potentially massive person group membership trees!
+ if (IGNORE_PARENT_ASSOC_TYPES.contains(parent.getTypeQName()))
+ {
+ continue;
+ }
+
// Add the inherited rule first
for (Rule rule : getInheritedRules(parent.getParentRef(), ruleTypeName, visitedNodeRefs))
{
@@ -1167,9 +1183,37 @@ public class RuleServiceImpl
// Execute the rule
boolean executeAsync = rule.getExecuteAsynchronously();
- this.actionService.executeAction(action, actionedUponNodeRef, true, executeAsync);
+ // ALF-718: Treats email actions as a special case where they may be performed after the
+ // current transaction is committed. This only deals with the bug fix and a more thorough approach
+ // (but one with potentially wide ranging consequences) is to replace the boolean executeAsynchronously
+ // property on Rules and Actions with an ExecutionTime property - which would
+ // be an enumerated type with members SYNCHRONOUSLY, SYNCRHONOUSLY_AFTER_COMMIT and ASYNCHRONOUSLY.
+ //
+ // NOTE: this code is not at the Action level (i.e. ActionService) since the logic of sending after
+ // successful commit works in the context of a Rule but not for the InvitationService.
+ if (action.getActionDefinitionName().equals(CompositeActionExecuter.NAME))
+ {
+ for (Action subAction : ((CompositeAction)action).getActions())
+ {
+ if (subAction.getActionDefinitionName().equals(MailActionExecuter.NAME))
+ {
+ subAction.setParameterValue(MailActionExecuter.PARAM_SEND_AFTER_COMMIT, true);
}
}
+ }
+ else if (action.getActionDefinitionName().equals(MailActionExecuter.NAME))
+ {
+ action.setParameterValue(MailActionExecuter.PARAM_SEND_AFTER_COMMIT, true);
+ }
+
+ executeAction(action, actionedUponNodeRef, executeAsync);
+ }
+ }
+
+ private void executeAction(Action action, NodeRef actionedUponNodeRef, boolean executeAsynchronously)
+ {
+ this.actionService.executeAction(action, actionedUponNodeRef, true, executeAsynchronously);
+ }
/**
* Determines whether the rule can be executed
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
index d54893b5dc..4ce058100f 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAO.java
@@ -83,7 +83,6 @@ public interface AuthorityDAO
*/
Set getContainingAuthorities(AuthorityType type, String name, boolean immediate);
-
/**
* Get a set of authorities with varying filter criteria
*
diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
index dc3c53cbcf..87e426be9a 100644
--- a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
+++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
@@ -782,25 +782,38 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
// If this top down search is not providing an adequate hit count then resort to a naiive unlimited search
if (processed >= maxToProcess)
{
+ Set unfilteredResult;
+ boolean filterZone;
if (authority == null)
{
- return new HashSet(getAuthorities(type, zoneName, null, false, true, new PagingRequest(0, maxResults, null)).getPage());
- }
- Set newResult = getContainingAuthorities(type, authority, false);
- result.clear();
- int i=0;
- for (String container : newResult)
- {
- if ((filter == null || filter.includeAuthority(container)
- && (zoneName == null || getAuthorityZones(container).contains(zoneName))))
+ unfilteredResult = new HashSet(getAuthorities(type, zoneName, null, false, true, new PagingRequest(0, filter == null ? maxResults : Integer.MAX_VALUE, null)).getPage());
+ if (filter == null)
{
- result.add(container);
+ return unfilteredResult;
+ }
+ filterZone = false;
+ }
+ else
+ {
+ unfilteredResult = getContainingAuthorities(type, authority, false);
+ filterZone = zoneName != null;
+ }
+ Set newResult = new TreeSet(result);
+ int i=newResult.size();
+ for (String container : unfilteredResult)
+ {
+ // Do not call the filter multiple times on the same result in case it is 'stateful'
+ if (!result.contains(container) && (filter == null || filter.includeAuthority(container))
+ && (!filterZone || getAuthorityZones(container).contains(zoneName)))
+ {
+ newResult.add(container);
if (++i >= maxResults)
{
break;
}
}
- }
+ }
+ result = newResult;
break;
}
}
diff --git a/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java b/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java
index d43602dbd0..113c224afc 100644
--- a/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java
+++ b/source/java/org/alfresco/repo/security/authority/script/ScriptGroup.java
@@ -57,7 +57,6 @@ public class ScriptGroup implements Authority, Serializable
private String fullName;
private String displayName;
private Set childAuthorityNames;
- private Boolean isAdmin;
private NodeRef groupNodeRef;
private Scriptable scope;
@@ -411,29 +410,6 @@ public class ScriptGroup implements Authority, Serializable
Set parents = authorityService.getContainingAuthorities(AuthorityType.GROUP, fullName, false);
return makeScriptGroups(parents, paging, sortBy, serviceRegistry, this.scope);
}
-
- /**
- * Is this a root group?
- * @return
- */
- public boolean isRootGroup()
- {
- ScriptGroup[] groups = getParentGroups();
- return (groups.length == 0);
- }
-
- /**
- * Is this an admin group?
- * @return
- */
- public boolean isAdminGroup()
- {
- if (this.isAdmin == null)
- {
- this.isAdmin = authorityService.isAdminAuthority(fullName);
- }
- return this.isAdmin;
- }
/**
* Get the number of users contained within this group.
diff --git a/source/java/org/alfresco/util/ModelUtil.java b/source/java/org/alfresco/util/ModelUtil.java
index f22e27a22d..4fca922f41 100644
--- a/source/java/org/alfresco/util/ModelUtil.java
+++ b/source/java/org/alfresco/util/ModelUtil.java
@@ -130,6 +130,7 @@ public class ModelUtil
{
return page(objects, new ScriptPagingDetails(maxItems, skipCount));
}
+
public static List page(Collection objects, ScriptPagingDetails paging)
{
int maxItems = paging.getMaxItems();