diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml
index 8c34c8b220..cb01bdddc5 100644
--- a/config/alfresco/patch/patch-services-context.xml
+++ b/config/alfresco/patch/patch-services-context.xml
@@ -51,7 +51,7 @@
-
+
@@ -2395,6 +2395,7 @@
+
diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml
index 0171a798b3..580386d246 100644
--- a/config/alfresco/public-services-context.xml
+++ b/config/alfresco/public-services-context.xml
@@ -1509,5 +1509,32 @@
-
+
+
+
+
+ org.alfresco.repo.tenant.TenantAdminService
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${server.transaction.mode.default}
+
+
+
+
diff --git a/config/alfresco/rule-services-context.xml b/config/alfresco/rule-services-context.xml
index deac3bf049..5823c48478 100644
--- a/config/alfresco/rule-services-context.xml
+++ b/config/alfresco/rule-services-context.xml
@@ -143,7 +143,7 @@
-
+
diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMToADMRemoteStorePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMToADMRemoteStorePatch.java
index e39e7e06d3..cf2959ac2d 100644
--- a/source/java/org/alfresco/repo/admin/patch/impl/AVMToADMRemoteStorePatch.java
+++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMToADMRemoteStorePatch.java
@@ -96,6 +96,8 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
private static final int MIGRATE_BATCH_THREADS = 4;
private static final int MIGRATE_BATCH_SIZE = 250;
+ private static final String SEPARATOR = "@";
+
private Map siteReferenceCache = null;
private SortedMap paths;
private SortedMap retryPaths;
@@ -198,11 +200,14 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
{
this.retryPaths = new TreeMap();
+ // get user names that will be used to RunAs and set permissions later
+ final String systemUser = AuthenticationUtil.getSystemUserName();
+
// firstly retrieve all AVM paths and descriptors that we need to process
// execute in a single transaction to retrieve the stateless object list
- RetryingTransactionCallback work = new RetryingTransactionCallback()
+ RetryingTransactionCallback work = new RetryingTransactionCallback()
{
- public Void execute() throws Exception
+ public String execute() throws Exception
{
long start = System.currentTimeMillis();
paths = retrieveAVMPaths();
@@ -220,21 +225,17 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
folderPath.add("user");
FileFolderUtil.makeFolders(fileFolderService, surfConfigRef, folderPath, ContentModel.TYPE_FOLDER);
- return null;
+ // return the tenant system user name while in the txn
+ return tenantAdminService.getDomainUser(systemUser, tenantAdminService.getCurrentUserDomain());
}
};
- this.transactionHelper.doInTransaction(work, false, true);
+ final String tenantSystemUser = this.transactionHelper.doInTransaction(work, false, true);
try
{
// init the siteid to surf-config noderef cache
this.siteReferenceCache = new ConcurrentHashMap(16384);
- // get user names that will be used to RunAs and set permissions later
- String systemUser = AuthenticationUtil.getSystemUserName();
- final String tenantSystemUser = this.tenantAdminService.getDomainUser(
- systemUser, this.tenantAdminService.getCurrentUserDomain());
-
// build a set of unique site names
final Set sites = new HashSet(paths.size());
Matcher matcher;
@@ -421,7 +422,7 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
if (this.retryPaths.size() != 0)
{
logger.info("Retrying " + this.retryPaths.size() + " paths...");
- work = new RetryingTransactionCallback()
+ RetryingTransactionCallback retrywork = new RetryingTransactionCallback()
{
public Void execute() throws Exception
{
@@ -432,7 +433,7 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
return null;
}
};
- this.transactionHelper.doInTransaction(work, false, true);
+ this.transactionHelper.doInTransaction(retrywork, false, true);
}
logger.info("Migrated: " + this.paths.size() + " AVM nodes to DM in " + (System.currentTimeMillis()-start) + "ms");
@@ -650,7 +651,16 @@ public class AVMToADMRemoteStorePatch extends AbstractPatch
SortedMap paths = new TreeMap();
- String avmPath = this.avmStore + ":" + this.avmRootPath;
+ String avmPath;
+ if (this.tenantAdminService.getCurrentUserDomain().isEmpty())
+ {
+ avmPath = this.avmStore + ":" + this.avmRootPath;
+ }
+ else
+ {
+ avmPath = SEPARATOR + this.tenantAdminService.getCurrentUserDomain() + SEPARATOR + this.avmStore + ":" + this.avmRootPath;
+ }
+
AVMNodeDescriptor node = this.avmService.lookup(-1, avmPath);
if (node != null)
{
diff --git a/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java b/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java
index c451a76537..6d6a8f1b01 100644
--- a/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java
+++ b/source/java/org/alfresco/repo/rule/MiscellaneousRulesTest.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertNotNull;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -36,6 +37,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.CopyService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@@ -50,6 +52,8 @@ import org.alfresco.util.test.junitrules.ApplicationContextInit;
import org.alfresco.util.test.junitrules.RunAsFullyAuthenticatedRule;
import org.alfresco.util.test.junitrules.TemporaryNodes;
import org.alfresco.util.test.junitrules.TemporarySites;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
@@ -68,6 +72,8 @@ import org.springframework.context.ApplicationContext;
*/
public class MiscellaneousRulesTest
{
+ private static final Log log = LogFactory.getLog(MiscellaneousRulesTest.class);
+
// Static JUnit Rules
public static ApplicationContextInit APP_CTXT_INIT = new ApplicationContextInit();
public static AlfrescoPerson TEST_USER = new AlfrescoPerson(APP_CTXT_INIT);
@@ -305,4 +311,74 @@ public class MiscellaneousRulesTest
}
});
}
+
+ @Test public void alf13192_rulesFromFirstFolderMoveToSecondWhenDeleteFirstFolder() throws Exception
+ {
+ final NodeRef testSiteDocLib = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public NodeRef execute() throws Throwable
+ {
+ return SITE_SERVICE.getContainer(testSite.getShortName(), SiteService.DOCUMENT_LIBRARY);
+ }
+ });
+ assertNotNull("Null doclib", testSiteDocLib);
+
+ final NodeRef folder1 = testNodes.createFolder(testSiteDocLib, "folder 1", TEST_USER.getUsername());
+ final NodeRef folder2 = testNodes.createFolder(testSiteDocLib, "folder 2", TEST_USER.getUsername());
+
+ // Put a rule on folder1.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ // Clashes with the JUnit annotation @Rule
+ org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
+ rule.setRuleType(RuleType.OUTBOUND);
+ rule.applyToChildren(false);
+ rule.setRuleDisabled(false);
+ rule.setTitle("Copy to folder2");
+ rule.setExecuteAsynchronously(false);
+
+ Map params = new HashMap();
+ params.put(CopyActionExecuter.PARAM_DESTINATION_FOLDER, folder2);
+ Action copyAction = ACTION_SERVICE.createAction("copy", params);
+ rule.setAction(copyAction);
+
+ RULE_SERVICE.saveRule(folder1, rule);
+
+ // While we're here, let's log some information about the rules.
+ List ruleFolders = NODE_SERVICE.getChildAssocs(folder1, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
+ assertEquals(1, ruleFolders.size());
+ log.debug("Rule SystemFolder noderef is " + ruleFolders.get(0).getChildRef());
+
+ return null;
+ }
+ });
+
+ // Now delete folder1.
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ log.debug("About to delete the ruled folder: " + folder1);
+
+ NODE_SERVICE.deleteNode(folder1);
+
+ return null;
+ }
+ });
+
+
+ // folder2 should have no rules-related elements
+ TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback()
+ {
+ public Void execute() throws Throwable
+ {
+ assertFalse(RULE_SERVICE.hasRules(folder2));
+ assertFalse(NODE_SERVICE.hasAspect(folder2, RuleModel.ASPECT_RULES));
+
+ return null;
+ }
+ });
+ }
}
diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
index 45c5427d20..778f7f08b1 100644
--- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
+++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTriggerAbstractBase.java
@@ -53,6 +53,7 @@ public abstract class RuleTriggerAbstractBase implements RuleTrigger
IGNORE_TYPES.add(ContentModel.TYPE_THUMBNAIL);
// Workaround to prevent rules running on cm:rating nodes (which happened for 'liked' folders ALF-8308 & ALF-8382)
IGNORE_TYPES.add(ContentModel.TYPE_RATING);
+ IGNORE_TYPES.add(ContentModel.TYPE_SYSTEM_FOLDER);
IGNORE_ASPECTS = new HashSet(13);
IGNORE_ASPECTS.add(ContentModel.ASPECT_TEMPORARY);
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/SolrJSONResultSet.java b/source/java/org/alfresco/repo/search/impl/lucene/SolrJSONResultSet.java
index db68d9f1d9..e70bc5d3dd 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/SolrJSONResultSet.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/SolrJSONResultSet.java
@@ -49,6 +49,8 @@ public class SolrJSONResultSet implements ResultSet
private ArrayList> page;
+ private ArrayList refs;
+
private ResultSetMetaData rsmd;
private Long status;
@@ -89,18 +91,23 @@ public class SolrJSONResultSet implements ResultSet
int numDocs = docs.length();
page = new ArrayList>(numDocs);
+ refs = new ArrayList(numDocs);
for(int i = 0; i < numDocs; i++)
{
JSONObject doc = docs.getJSONObject(i);
JSONArray dbids = doc.getJSONArray("DBID");
Long dbid = dbids.getLong(0);
Float score = Float.valueOf(doc.getString("score"));
- page.add(new Pair(dbid, score));
- for(Iterator it = doc.keys(); it.hasNext(); /* */)
+ NodeRef nodeRef = nodeService.getNodeRef(dbid);
+
+ if(nodeRef != null)
{
- String key = (String)it.next();
+ page.add(new Pair(dbid, score));
+ refs.add(nodeRef);
}
+
+
}
if(json.has("facet_counts"))
@@ -212,16 +219,7 @@ public class SolrJSONResultSet implements ResultSet
@Override
public NodeRef getNodeRef(int n)
{
- // TODO: lost nodes?
- NodeRef nodeRef = nodeService.getNodeRef(page.get(n).getFirst());
- if(nodeRef != null)
- {
- return nodeRef;
- }
- else
- {
- return new NodeRef(new StoreRef("missing", "missing"), "missing");
- }
+ return refs.get(n);
}
/*
@@ -231,12 +229,7 @@ public class SolrJSONResultSet implements ResultSet
@Override
public List getNodeRefs()
{
- ArrayList refs = new ArrayList(page.size());
- for(int i = 0; i < page.size(); i++ )
- {
- refs.add( getNodeRef(i));
- }
- return refs;
+ return Collections.unmodifiableList(refs);
}
/*
diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
index 6aadca05f0..7f48425a01 100644
--- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
+++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java
@@ -73,6 +73,7 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.invitation.InvitationException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
+import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -1282,11 +1283,14 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
final List personInfos = new ArrayList(nodeRefs.size());
for (NodeRef nodeRef : nodeRefs)
{
- Map props = nodeService.getProperties(nodeRef);
- personInfos.add(new PersonInfo(nodeRef,
- (String)props.get(ContentModel.PROP_USERNAME),
- (String)props.get(ContentModel.PROP_FIRSTNAME),
- (String)props.get(ContentModel.PROP_LASTNAME)));
+ if (nodeService.exists(nodeRef))
+ {
+ Map props = nodeService.getProperties(nodeRef);
+ personInfos.add(new PersonInfo(nodeRef,
+ (String)props.get(ContentModel.PROP_USERNAME),
+ (String)props.get(ContentModel.PROP_FIRSTNAME),
+ (String)props.get(ContentModel.PROP_LASTNAME)));
+ }
}
return new PagingResults()