diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index b740be24fd..100fb988ac 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -126,7 +126,7 @@ - + @@ -139,6 +139,7 @@ + diff --git a/source/java/org/alfresco/repo/node/NodeArchiveServicePolicies.java b/source/java/org/alfresco/repo/node/NodeArchiveServicePolicies.java new file mode 100644 index 0000000000..2aa82cdc2f --- /dev/null +++ b/source/java/org/alfresco/repo/node/NodeArchiveServicePolicies.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.node; + +import org.alfresco.repo.policy.ClassPolicy; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +/** + * Node archive service policies + * + * @author Viachaslau Tsikhanovich + */ +public interface NodeArchiveServicePolicies +{ + public interface BeforePurgeNodePolicy extends ClassPolicy + { + public static final QName QNAME = QName.createQName(NamespaceService.ALFRESCO_URI, "beforePurgeNode"); + /** + * Called before a node is purged (deleted from archive). + * + * @param nodeRef the node reference + */ + public void beforePurgeNode(NodeRef nodeRef); + } +} diff --git a/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java b/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java index db40799eeb..29f3cddd90 100644 --- a/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java +++ b/source/java/org/alfresco/repo/node/archive/NodeArchiveServiceImpl.java @@ -21,7 +21,9 @@ package org.alfresco.repo.node.archive; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; @@ -35,7 +37,11 @@ import org.alfresco.repo.batch.BatchProcessor; import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker; import org.alfresco.repo.lock.JobLockService; import org.alfresco.repo.lock.LockAcquisitionException; +import org.alfresco.repo.node.NodeArchiveServicePolicies; +import org.alfresco.repo.node.NodeArchiveServicePolicies.BeforePurgeNodePolicy; import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus; +import org.alfresco.repo.policy.ClassPolicyDelegate; +import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.AccessDeniedException; @@ -86,6 +92,15 @@ public class NodeArchiveServiceImpl implements NodeArchiveService private TenantService tenantService; private boolean userNamesAreCaseSensitive = false; + /** controls policy delegates */ + private PolicyComponent policyComponent; + private ClassPolicyDelegate beforePurgeNodeDelegate; + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; @@ -110,7 +125,13 @@ public class NodeArchiveServiceImpl implements NodeArchiveService { this.jobLockService = jobLockService; } - + + public void init() + { + // Register the various policies + beforePurgeNodeDelegate = policyComponent.registerClassPolicy(NodeArchiveServicePolicies.BeforePurgeNodePolicy.class); + } + public void setAuthorityService(AuthorityService authorityService) { this.authorityService = authorityService; @@ -474,6 +495,7 @@ public class NodeArchiveServiceImpl implements NodeArchiveService { try { + invokeBeforePurgeNode(archivedNodeRef); nodeService.deleteNode(archivedNodeRef); } catch (InvalidNodeRefException e) @@ -524,6 +546,7 @@ public class NodeArchiveServiceImpl implements NodeArchiveService AuthenticationUtil.setFullyAuthenticatedUser(user); if (nodeService.exists(nodeRef)) { + invokeBeforePurgeNode(nodeRef); nodeService.deleteNode(nodeRef); } } @@ -748,4 +771,52 @@ public class NodeArchiveServiceImpl implements NodeArchiveService } return currentUser; } + + protected void invokeBeforePurgeNode(NodeRef nodeRef) + { + if (ignorePolicy(nodeRef)) + { + return; + } + + // get qnames to invoke against + Set qnames = getTypeAndAspectQNames(nodeRef); + // execute policy for node type and aspects + NodeArchiveServicePolicies.BeforePurgeNodePolicy policy = beforePurgeNodeDelegate.get(nodeRef, qnames); + policy.beforePurgeNode(nodeRef); + } + + /** + * Get all aspect and node type qualified names + * + * @param nodeRef + * the node we are interested in + * @return Returns a set of qualified names containing the node type and all + * the node aspects, or null if the node no longer exists + */ + protected Set getTypeAndAspectQNames(NodeRef nodeRef) + { + Set qnames = null; + try + { + Set aspectQNames = nodeService.getAspects(nodeRef); + + QName typeQName = nodeService.getType(nodeRef); + + qnames = new HashSet(aspectQNames.size() + 1); + qnames.addAll(aspectQNames); + qnames.add(typeQName); + } + catch (InvalidNodeRefException e) + { + qnames = Collections.emptySet(); + } + // done + return qnames; + } + + private boolean ignorePolicy(NodeRef nodeRef) + { + return false; + } } diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index fde22ca01e..d2de11e48e 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -47,8 +47,8 @@ import org.alfresco.query.PagingResults; import org.alfresco.repo.activities.ActivityType; import org.alfresco.repo.admin.SysAdminParams; import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.node.NodeServicePolicies; -import org.alfresco.repo.node.NodeServicePolicies.OnRestoreNodePolicy; +import org.alfresco.repo.node.NodeArchiveServicePolicies; +import org.alfresco.repo.node.NodeArchiveServicePolicies.BeforePurgeNodePolicy; import org.alfresco.repo.node.getchildren.FilterProp; import org.alfresco.repo.node.getchildren.FilterPropString; import org.alfresco.repo.node.getchildren.FilterPropString.FilterTypeString; @@ -115,7 +115,7 @@ import org.springframework.extensions.surf.util.ParameterCheck; * * @author Roy Wetherall */ -public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServiceInternal, SiteModel, NodeServicePolicies.OnRestoreNodePolicy +public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServiceInternal, SiteModel, NodeArchiveServicePolicies.BeforePurgeNodePolicy { /** Logger */ protected static Log logger = LogFactory.getLog(SiteServiceImpl.class); @@ -390,9 +390,9 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic protected void onBootstrap(ApplicationEvent event) { this.policyComponent.bindClassBehaviour( - OnRestoreNodePolicy.QNAME, + BeforePurgeNodePolicy.QNAME, SiteModel.TYPE_SITE, - new JavaBehaviour(this, "onRestoreNode")); + new JavaBehaviour(this, "beforePurgeNode")); } /* (non-Javadoc) @@ -465,7 +465,7 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic // Check to see if we already have a site of this name NodeRef existingSite = getSiteNodeRef(shortName, false); - if (existingSite != null) + if (existingSite != null || authorityService.authorityExists(getSiteGroup(shortName, true))) { // Throw an exception since we have a duplicate site name throw new SiteServiceException(MSG_UNABLE_TO_CREATE, new Object[]{shortName}); @@ -1463,40 +1463,11 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic { throw new SiteServiceException(MSG_CAN_NOT_DELETE, new Object[]{shortName}); } - final QName siteType = this.directNodeService.getType(siteNodeRef); // Delete the cached reference siteNodeRefCache.remove(shortName); - // Get and retain the membership of the site we're deleting. We do this to support restoration of a site node from the trashcan. - AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() - { - public Void doWork() throws Exception - { - final String siteGroup = getSiteGroup(shortName, true); - if (authorityService.authorityExists(siteGroup)) - { - // Collection for recording the group memberships present on the site - final Map> groupsMemberships = new HashMap>(); - - // Iterate over the role related groups and delete then - Set permissions = permissionService.getSettablePermissions(siteType); - for (String permission : permissions) - { - String siteRoleGroup = getSiteRoleGroup(shortName, permission, true); - - // Collect up the memberships so we can potentially restore them later - Set groupUsers = authorityService.getContainedAuthorities(null, siteRoleGroup, true); - groupsMemberships.put(siteRoleGroup, groupUsers); - } - - // Save the group memberships so we can use them later - nodeService.setProperty(siteNodeRef, QName.createQName(null, "memberships"), (Serializable)groupsMemberships); - } - - return null; - } - }, AuthenticationUtil.getSystemUserName()); + // no need to retain the membership of the site as we postpone delete of authorities until purge from the trashcan // The default behaviour is that sites cannot be deleted. But we disable that behaviour here // in order to allow site deletion only via this service. Share calls this service for deletion. @@ -1517,6 +1488,18 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic this.behaviourFilter.enableBehaviour(siteParent, ContentModel.ASPECT_AUDITABLE); } + // Postpone delete of associated groups to the time when NodeArchiveService purges site node + // because in case of recover ACLs and ACEs are needed which were set for documents + + logger.debug("site deleted :" + shortName); + } + + @Override + public void beforePurgeNode(NodeRef nodeRef) + { + final QName siteType = this.directNodeService.getType(nodeRef); + final String shortName = getSite(nodeRef).getShortName(); + // Delete the associated groups AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { @@ -1527,39 +1510,22 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic if (authorityService.authorityExists(siteGroup)) { authorityService.deleteAuthority(siteGroup, false); - + // Iterate over the role related groups and delete then Set permissions = permissionService.getSettablePermissions(siteType); for (String permission : permissions) { String siteRoleGroup = getSiteRoleGroup(shortName, permission, true); - + // Delete the site role group authorityService.deleteAuthority(siteRoleGroup); } } - + return null; } }, AuthenticationUtil.getSystemUserName()); - - logger.debug("site deleted :" + shortName); - } - - /** - * @see org.alfresco.repo.node.NodeServicePolicies.OnRestoreNodePolicy#onRestoreNode(org.alfresco.service.cmr.repository.ChildAssociationRef) - */ - @SuppressWarnings("unchecked") - @Override - public void onRestoreNode(ChildAssociationRef childAssocRef) - { - // regenerate the groups for the site when it is restored from the Archive store - NodeRef siteRef = childAssocRef.getChildRef(); - setupSitePermissions( - siteRef, - (String)directNodeService.getProperty(siteRef, ContentModel.PROP_NAME), - getSiteVisibility(siteRef), - (Map>)directNodeService.getProperty(siteRef, QName.createQName(null, "memberships"))); + } public void listMembers(String shortName, final String nameFilter, final String roleFilter, final boolean collapseGroups, final SiteMembersCallback callback) @@ -2998,4 +2964,5 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic this.permissionService.setInheritParentPermissions(containerNodeRef, false); } + } diff --git a/source/test-java/org/alfresco/repo/activities/AbstractSiteActivityTest.java b/source/test-java/org/alfresco/repo/activities/AbstractSiteActivityTest.java index 7b955c6dd1..5437d5a0cb 100644 --- a/source/test-java/org/alfresco/repo/activities/AbstractSiteActivityTest.java +++ b/source/test-java/org/alfresco/repo/activities/AbstractSiteActivityTest.java @@ -28,6 +28,7 @@ import org.alfresco.repo.activities.feed.FeedGenerator; import org.alfresco.repo.activities.feed.local.LocalFeedTaskProcessor; import org.alfresco.repo.activities.post.lookup.PostLookup; import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.site.SiteModel; @@ -35,6 +36,7 @@ import org.alfresco.service.cmr.activities.ActivityService; import org.alfresco.service.cmr.activities.FeedControl; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.util.ApplicationContextHelper; @@ -65,6 +67,7 @@ public abstract class AbstractSiteActivityTest private PersonService personService; private PostLookup postLookup; private FeedGenerator feedGenerator; + private NodeArchiveService nodeArchiveService; // // Test config & data @@ -116,6 +119,7 @@ public abstract class AbstractSiteActivityTest this.siteService = (SiteService)applicationContext.getBean("SiteService"); this.authenticationService = (MutableAuthenticationService)applicationContext.getBean("AuthenticationService"); this.personService = (PersonService)applicationContext.getBean("PersonService"); + this.nodeArchiveService = (NodeArchiveService)applicationContext.getBean("nodeArchiveService"); LocalFeedTaskProcessor feedProcessor = null; @@ -196,8 +200,13 @@ public abstract class AbstractSiteActivityTest protected void deleteSite(String siteId) throws Exception { - // delete site (and site's associated groups) - siteService.deleteSite(siteId); + SiteInfo siteInfo = siteService.getSite(siteId); + if (siteInfo != null) + { + // delete site (and site's associated groups) + siteService.deleteSite(siteId); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); + } } @Test diff --git a/source/test-java/org/alfresco/repo/activities/ActivityServiceImplTest.java b/source/test-java/org/alfresco/repo/activities/ActivityServiceImplTest.java index 4a1c0f5040..e7b58cbdf4 100644 --- a/source/test-java/org/alfresco/repo/activities/ActivityServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/activities/ActivityServiceImplTest.java @@ -27,6 +27,7 @@ import junit.framework.TestCase; import org.alfresco.repo.domain.activities.ActivityPostDAO; import org.alfresco.repo.domain.activities.ActivityPostEntity; import org.alfresco.repo.jscript.ClasspathScriptLocation; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.activities.ActivityService; import org.alfresco.service.cmr.activities.FeedControl; @@ -34,6 +35,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.ScriptLocation; import org.alfresco.service.cmr.repository.ScriptService; import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.test_category.OwnJVMTestsCategory; @@ -57,6 +59,7 @@ public class ActivityServiceImplTest extends TestCase private MutableAuthenticationService authenticationService; private SiteService siteService; private ActivityPostDAO postDAO; + private NodeArchiveService nodeArchiveService; private static final String ADMIN_PW = "admin"; @@ -71,6 +74,7 @@ public class ActivityServiceImplTest extends TestCase activityService = (ActivityService)ctx.getBean("activityService"); scriptService = (ScriptService)ctx.getBean("ScriptService"); siteService = (SiteService)ctx.getBean("SiteService"); + nodeArchiveService = (NodeArchiveService)ctx.getBean("nodeArchiveService"); postDAO = (ActivityPostDAO)ctx.getBean("postDAO"); @@ -145,7 +149,9 @@ public class ActivityServiceImplTest extends TestCase assertNotNull(siteFeedEntries); assertTrue(siteFeedEntries.isEmpty()); + SiteInfo siteInfo = siteService.getSite(siteId); siteService.deleteSite(siteId); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); } public void testGetEmptyUserFeed() throws Exception diff --git a/source/test-java/org/alfresco/repo/activities/feed/cleanup/AbstractFeedCleanerTest.java b/source/test-java/org/alfresco/repo/activities/feed/cleanup/AbstractFeedCleanerTest.java index f0366e39b7..4374d3f2b7 100644 --- a/source/test-java/org/alfresco/repo/activities/feed/cleanup/AbstractFeedCleanerTest.java +++ b/source/test-java/org/alfresco/repo/activities/feed/cleanup/AbstractFeedCleanerTest.java @@ -30,11 +30,13 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.activities.ActivityFeedDAO; import org.alfresco.repo.domain.activities.ActivityFeedEntity; import org.alfresco.repo.lock.JobLockService; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.util.ApplicationContextHelper; @@ -61,7 +63,8 @@ public abstract class AbstractFeedCleanerTest private SiteService siteService; private PersonService personService; protected RetryingTransactionHelper transactionHelper; - + private NodeArchiveService nodeArchiveService; + private static final String TEST_SITE = "testSite"; private static final String TEST_SITE_1 = TEST_SITE+"1"; @@ -91,7 +94,8 @@ public abstract class AbstractFeedCleanerTest personService = (PersonService) ctx.getBean("PersonService"); feedDAO = (ActivityFeedDAO) ctx.getBean("feedDAO"); transactionHelper = (RetryingTransactionHelper)ctx.getBean("retryingTransactionHelper"); - + nodeArchiveService = (NodeArchiveService)ctx.getBean("nodeArchiveService"); + // Let's shut down the scheduler so that we aren't competing with the scheduled versions of jobs (ie. feed cleaner) Scheduler scheduler = (Scheduler) ctx.getBean("schedulerFactory"); scheduler.shutdown(); @@ -124,9 +128,11 @@ public abstract class AbstractFeedCleanerTest for (int i = 1; i <= 7; i++) { - if (siteService.getSite("testSite"+i) != null) + SiteInfo site = siteService.getSite("testSite"+i); + if (site != null) { siteService.deleteSite("testSite"+i); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(site.getNodeRef())); } } @@ -372,8 +378,10 @@ public abstract class AbstractFeedCleanerTest assertEquals(site4FeedCnt, feedDAO.selectSiteFeedEntries(TEST_SITE_4, -1).size()); assertEquals(site4FeedCnt+site5FeedCnt, feedDAO.selectUserFeedEntries(TEST_USER_D, null, false, false,-1L, -1).size()); + SiteInfo site = siteService.getSite(TEST_SITE_4); // delete the site siteService.deleteSite(TEST_SITE_4); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(site.getNodeRef())); // note: site feed cleanup is done in separate txn after commit transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback() diff --git a/source/test-java/org/alfresco/repo/googledocs/GoogleDocumentServiceSystemTest.java b/source/test-java/org/alfresco/repo/googledocs/GoogleDocumentServiceSystemTest.java index 31275a9c05..59e0ba316d 100644 --- a/source/test-java/org/alfresco/repo/googledocs/GoogleDocumentServiceSystemTest.java +++ b/source/test-java/org/alfresco/repo/googledocs/GoogleDocumentServiceSystemTest.java @@ -32,6 +32,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.transform.AbstractContentTransformerTest; import org.alfresco.repo.management.subsystems.ApplicationContextFactory; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.rendition.executer.AbstractRenderingEngine; import org.alfresco.repo.rendition.executer.ReformatRenderingEngine; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -47,6 +48,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.NamespaceService; @@ -73,6 +75,7 @@ public class GoogleDocumentServiceSystemTest extends TestCase implements GoogleD private PersonService personService; private ApplicationContextFactory subsystem; private RenditionService renditionService; + private NodeArchiveService nodeArchiveService; private static final String USER_ONE = "GoogleDocUserOne"; private static final String USER_TWO = "GoogleDocUserTwo"; @@ -105,6 +108,7 @@ public class GoogleDocumentServiceSystemTest extends TestCase implements GoogleD authenticationService = (MutableAuthenticationService)appContext.getBean("authenticationService"); personService = (PersonService)appContext.getBean("personService"); renditionService = (RenditionService)appContext.getBean("renditionService"); + nodeArchiveService = (NodeArchiveService)appContext.getBean("nodeArchiveService"); // Start the user transaction userTransaction = transactionService.getUserTransaction(); @@ -206,12 +210,14 @@ public class GoogleDocumentServiceSystemTest extends TestCase implements GoogleD @Override protected void tearDown() throws Exception { + SiteInfo siteInfo = siteService.getSite(siteId); siteService.deleteSite(siteId); if (userTransaction != null) { userTransaction.commit(); } + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); } private boolean isGoogleServiceAvailable() diff --git a/source/test-java/org/alfresco/repo/publishing/flickr/FlickrTest.java b/source/test-java/org/alfresco/repo/publishing/flickr/FlickrTest.java index 0afae023ff..4789fbb887 100644 --- a/source/test-java/org/alfresco/repo/publishing/flickr/FlickrTest.java +++ b/source/test-java/org/alfresco/repo/publishing/flickr/FlickrTest.java @@ -25,6 +25,7 @@ import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.publishing.Environment; import org.alfresco.repo.publishing.PublishingModel; import org.alfresco.repo.publishing.PublishingQueueImpl; @@ -39,6 +40,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.NamespaceService; @@ -67,6 +69,7 @@ public class FlickrTest extends BaseSpringTest protected PublishingQueueImpl queue; protected Environment environment; protected NodeRef docLib; + protected NodeArchiveService nodeArchiveService; private ChannelService channelService; @@ -76,6 +79,7 @@ public class FlickrTest extends BaseSpringTest { serviceRegistry = (ServiceRegistry) getApplicationContext().getBean("ServiceRegistry"); channelService = (ChannelService) getApplicationContext().getBean("channelService"); + nodeArchiveService = (NodeArchiveService) getApplicationContext().getBean("nodeArchiveService"); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); siteService = serviceRegistry.getSiteService(); fileFolderService = serviceRegistry.getFileFolderService(); @@ -90,7 +94,12 @@ public class FlickrTest extends BaseSpringTest public void onTearDown() { - siteService.deleteSite(siteId); + SiteInfo siteInfo = siteService.getSite(siteId); + if (siteInfo != null) + { + siteService.deleteSite(siteId); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); + } } public void testBlank() diff --git a/source/test-java/org/alfresco/repo/publishing/slideshare/SlideShareTest.java b/source/test-java/org/alfresco/repo/publishing/slideshare/SlideShareTest.java index e923d5b4e2..e35409238d 100644 --- a/source/test-java/org/alfresco/repo/publishing/slideshare/SlideShareTest.java +++ b/source/test-java/org/alfresco/repo/publishing/slideshare/SlideShareTest.java @@ -29,6 +29,7 @@ import java.util.TreeMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.publishing.Environment; import org.alfresco.repo.publishing.PublishingModel; import org.alfresco.repo.publishing.PublishingQueueImpl; @@ -44,6 +45,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.NamespaceService; @@ -75,6 +77,7 @@ public class SlideShareTest extends BaseSpringTest protected NodeRef docLib; protected Map testFiles = new TreeMap(); protected Map testNodeMap = new HashMap(); + protected NodeArchiveService nodeArchiveService; private ChannelService channelService; @@ -84,6 +87,7 @@ public class SlideShareTest extends BaseSpringTest { serviceRegistry = (ServiceRegistry) getApplicationContext().getBean("ServiceRegistry"); channelService = (ChannelService) getApplicationContext().getBean("channelService"); + nodeArchiveService = (NodeArchiveService) getApplicationContext().getBean("nodeArchiveService"); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); siteService = serviceRegistry.getSiteService(); fileFolderService = serviceRegistry.getFileFolderService(); @@ -103,7 +107,12 @@ public class SlideShareTest extends BaseSpringTest public void onTearDown() { - siteService.deleteSite(siteId); + SiteInfo siteInfo = siteService.getSite(siteId); + if (siteInfo != null) + { + siteService.deleteSite(siteId); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); + } } public void testBlank() diff --git a/source/test-java/org/alfresco/repo/publishing/youtube/YouTubeTest.java b/source/test-java/org/alfresco/repo/publishing/youtube/YouTubeTest.java index 297db0fea0..f7831a16b8 100644 --- a/source/test-java/org/alfresco/repo/publishing/youtube/YouTubeTest.java +++ b/source/test-java/org/alfresco/repo/publishing/youtube/YouTubeTest.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.Map; import org.alfresco.model.ContentModel; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.publishing.Environment; import org.alfresco.repo.publishing.PublishingModel; import org.alfresco.repo.publishing.PublishingQueueImpl; @@ -38,6 +39,7 @@ import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; import org.alfresco.service.namespace.NamespaceService; @@ -66,6 +68,7 @@ public class YouTubeTest extends BaseSpringTest protected PublishingQueueImpl queue; protected Environment environment; protected NodeRef docLib; + protected NodeArchiveService nodeArchiveService; private ChannelService channelService; @@ -75,6 +78,7 @@ public class YouTubeTest extends BaseSpringTest { serviceRegistry = (ServiceRegistry) getApplicationContext().getBean("ServiceRegistry"); channelService = (ChannelService) getApplicationContext().getBean("channelService"); + nodeArchiveService = (NodeArchiveService) getApplicationContext().getBean("nodeArchiveService"); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); siteService = serviceRegistry.getSiteService(); fileFolderService = serviceRegistry.getFileFolderService(); @@ -89,7 +93,12 @@ public class YouTubeTest extends BaseSpringTest public void onTearDown() { - siteService.deleteSite(siteId); + SiteInfo siteInfo = siteService.getSite(siteId); + if (siteInfo != null) + { + siteService.deleteSite(siteId); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); + } } public void testBlank() diff --git a/source/test-java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/source/test-java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index 81521ace94..9d9e357d93 100644 --- a/source/test-java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/source/test-java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -39,6 +39,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingResults; import org.alfresco.repo.domain.permissions.AclDAO; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; @@ -48,6 +49,7 @@ import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ChildAssociationRef; 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.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; @@ -78,6 +80,7 @@ public class AuthorityServiceTest extends TestCase private AclDAO aclDaoComponent; private NodeService nodeService; private AuthorityBridgeTableAsynchronouslyRefreshedCache authorityBridgeTableCache; + private NodeArchiveService nodeArchiveService; public AuthorityServiceTest() { @@ -110,10 +113,14 @@ public class AuthorityServiceTest extends TestCase aclDaoComponent = (AclDAO) ctx.getBean("aclDAO"); nodeService = (NodeService) ctx.getBean("nodeService"); authorityBridgeTableCache = (AuthorityBridgeTableAsynchronouslyRefreshedCache) ctx.getBean("authorityBridgeTableCache"); + nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService"); String defaultAdminUser = AuthenticationUtil.getAdminUserName(); AuthenticationUtil.setFullyAuthenticatedUser(defaultAdminUser); + // cleanup trashcan + nodeArchiveService.purgeAllArchivedNodes(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE); + // note: currently depends on any existing (and/or bootstrap) group data - eg. default site "swsdp" (Sample Web Site Design Project) SiteService siteService = (SiteService) ctx.getBean("SiteService"); SITE_CNT = siteService.listSites(defaultAdminUser).size(); diff --git a/source/test-java/org/alfresco/repo/site/SiteServiceImplMoreTest.java b/source/test-java/org/alfresco/repo/site/SiteServiceImplMoreTest.java index a746c1e823..24177fd7f3 100644 --- a/source/test-java/org/alfresco/repo/site/SiteServiceImplMoreTest.java +++ b/source/test-java/org/alfresco/repo/site/SiteServiceImplMoreTest.java @@ -23,9 +23,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.Set; +import org.alfresco.model.ContentModel; import org.alfresco.query.PagingRequest; import org.alfresco.query.PagingResults; import org.alfresco.repo.node.archive.NodeArchiveService; @@ -35,10 +38,14 @@ 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.ChildAssociationRef; 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.security.AccessPermission; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.site.SiteVisibility; @@ -105,6 +112,7 @@ public class SiteServiceImplMoreTest private static NodeArchiveService NODE_ARCHIVE_SERVICE; private static SiteService SITE_SERVICE; private static RetryingTransactionHelper TRANSACTION_HELPER; + private static PermissionService PERMISSION_SERVICE; private static String TEST_SITE_NAME, TEST_SUB_SITE_NAME; private static TestSiteAndMemberInfo TEST_SITE_WITH_MEMBERS; @@ -117,6 +125,8 @@ public class SiteServiceImplMoreTest NODE_ARCHIVE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("nodeArchiveService", NodeArchiveService.class); SITE_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("siteService", SiteService.class); TRANSACTION_HELPER = APP_CONTEXT_INIT.getApplicationContext().getBean("retryingTransactionHelper", RetryingTransactionHelper.class); + PERMISSION_SERVICE = APP_CONTEXT_INIT.getApplicationContext().getBean("permissionServiceImpl", PermissionService.class); + // We'll create this test content as admin. final String admin = AuthenticationUtil.getAdminUserName(); @@ -207,11 +217,31 @@ public class SiteServiceImplMoreTest final TestSiteAndMemberInfo testSiteAndMemberInfo = perMethodTestSites.createTestSiteWithUserPerRole(siteShortName, "sitePreset", SiteVisibility.PUBLIC, AuthenticationUtil.getAdminUserName()); // Now get the various site-related data that we want to examine after deletion & restoration - final Map userNameToRoleMap = - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback>() + final TestData testData = + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback() { - public Map execute() throws Throwable + public TestData execute() throws Throwable { + Map properties = new HashMap(); + properties.put(ContentModel.PROP_NAME, "testcontent"); + properties.put(ContentModel.PROP_DESCRIPTION, "content - test doc for test"); + ChildAssociationRef testDoc = NODE_SERVICE.createNode(testSiteAndMemberInfo.doclib, ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "testcontent"), + ContentModel.TYPE_CONTENT, properties); + NodeRef testDocNodeRef = testDoc.getChildRef(); + + // change all groups to have the permissions from a contributor + PERMISSION_SERVICE.deletePermissions(testDocNodeRef); + PERMISSION_SERVICE.setInheritParentPermissions(testDocNodeRef, false); + assertTrue("Permissions should be cleared", PERMISSION_SERVICE.getAllSetPermissions(testDocNodeRef).isEmpty()); + + Set permissions = PERMISSION_SERVICE.getSettablePermissions(SiteModel.TYPE_SITE); + for (String permission : permissions) + { + String siteRoleGroup = SITE_SERVICE.getSiteRoleGroup(siteShortName, permission); + PERMISSION_SERVICE.setPermission(testDocNodeRef, siteRoleGroup, "SiteContributor", true); + } + final Map userNameToRoleMap = new HashMap(); // Which users are members of which groups? @@ -232,7 +262,7 @@ public class SiteServiceImplMoreTest SITE_SERVICE.deleteSite(siteShortName); log.debug("Site deleted."); - return userNameToRoleMap; + return new TestData(userNameToRoleMap, testDocNodeRef); } }); @@ -257,9 +287,9 @@ public class SiteServiceImplMoreTest } }); - TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback() + final Map associatedGroups = TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback>() { - public Void execute() throws Throwable + public Map execute() throws Throwable { // The site itself should have been restored, of course... assertTrue("The site noderef was not restored as expected", NODE_SERVICE.exists(testSiteAndMemberInfo.siteInfo.getNodeRef())); @@ -276,16 +306,66 @@ public class SiteServiceImplMoreTest for (Map.Entry entry : SITE_SERVICE.listMembers(siteShortName, null, null, 0, true).entrySet()) { log.debug(entry); } // And finally, the original members of the site should have been given the same membership that they had before. - for (Map.Entry entry : userNameToRoleMap.entrySet()) + for (Map.Entry entry : testData.userNameToRoleMap.entrySet()) { assertEquals("Unexpected role for site user: " + entry.getKey(), entry.getValue(), SITE_SERVICE.getMembersRole(siteShortName, entry.getKey())); } + // When the site is restored custom permissions on contents should be also restored + Set accessPermissions = PERMISSION_SERVICE.getAllSetPermissions(testData.testDocNodeRef); + Map associatedGroups = new HashMap(); + for(AccessPermission access : accessPermissions) + { + associatedGroups.put(access.getAuthority(), access.getPermission()); + } + Set permissions = PERMISSION_SERVICE.getSettablePermissions(SiteModel.TYPE_SITE); + for (String permission : permissions) + { + String siteRoleGroup = SITE_SERVICE.getSiteRoleGroup(siteShortName, permission); + assertTrue("all groups should have the permissions from a contributor on test content", "SiteContributor".equals(associatedGroups.get(siteRoleGroup))); + } + + return associatedGroups; + } + }); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + log.debug("About to delete site completely."); + SITE_SERVICE.deleteSite(siteShortName); + for (String authority : associatedGroups.keySet()) + { + assertTrue("Associated groups should remain after site delete", AUTHORITY_SERVICE.authorityExists(authority)); + } + return null; } }); + + TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + log.debug("About to purge site from trashcan."); + + // get archive node reference + String storePath = "archive://SpacesStore"; + StoreRef storeRef = new StoreRef(storePath); + NodeRef archivedNodeRef = new NodeRef(storeRef, testSiteAndMemberInfo.siteInfo.getNodeRef().getId()); + NODE_ARCHIVE_SERVICE.purgeArchivedNode(archivedNodeRef); + for (String authority : associatedGroups.keySet()) + { + assertTrue("Associated groups should be deleted on site purge", !AUTHORITY_SERVICE.authorityExists(authority)); + } + + return null; + } + }); + } private void assertThatArchivedNodeExists(NodeRef originalNodeRef, String failureMsg) @@ -293,4 +373,16 @@ public class SiteServiceImplMoreTest final NodeRef archivedNodeRef = NODE_ARCHIVE_SERVICE.getArchivedNode(originalNodeRef); assertTrue(failureMsg, NODE_SERVICE.exists(archivedNodeRef)); } + + public static class TestData + { + public final Map userNameToRoleMap; + public final NodeRef testDocNodeRef; + + public TestData(Map userNameToRoleMap, NodeRef testDocNodeRef) + { + this.userNameToRoleMap = userNameToRoleMap; + this.testDocNodeRef = testDocNodeRef; + } + } } diff --git a/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java b/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java index 3ab6adafb8..ea56368729 100644 --- a/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java @@ -800,9 +800,8 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest { return authorityService.createAuthority(AuthorityType.GROUP, testGroupName); } - }, AuthenticationUtil.getAdminUserName()); - + // Create a test site String siteShortName = "testUpdateSite"; this.siteService.createSite(TEST_SITE_PRESET, siteShortName, TEST_TITLE, TEST_DESCRIPTION, SiteVisibility.PUBLIC); @@ -817,14 +816,15 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest assertNull(this.siteService.getSite(siteShortName)); NodeRef archivedNodeRef = nodeArchiveService.getArchivedNode(siteInfo.getNodeRef()); assertTrue("Deleted sites can be recovered from the Trash.", nodeService.exists(archivedNodeRef)); - - // Ensure that all the related site groups are deleted - assertFalse(authorityService.authorityExists(((SiteServiceImpl)smallSiteService).getSiteGroup(siteShortName, true))); + + // related site groups should remain after site delete but should be deleted on site purge from trashcan. + // Such case is tested in SiteServiceImplMoreTest.deleteSiteAndRestoreEnsuringSiteGroupsAreRecovered + assertTrue(authorityService.authorityExists(((SiteServiceImpl)smallSiteService).getSiteGroup(siteShortName, true))); Set permissions = permissionService.getSettablePermissions(SiteModel.TYPE_SITE); for (String permission : permissions) { String siteRoleGroup = ((SiteServiceImpl)smallSiteService).getSiteRoleGroup(siteShortName, permission, true); - assertFalse(authorityService.authorityExists(siteRoleGroup)); + assertTrue(authorityService.authorityExists(siteRoleGroup)); } // Ensure that the added "normal" groups have not been deleted diff --git a/source/test-java/org/alfresco/repo/subscriptions/SubscriptionServiceActivitiesTest.java b/source/test-java/org/alfresco/repo/subscriptions/SubscriptionServiceActivitiesTest.java index 5d68fc4e3b..a001d9683a 100644 --- a/source/test-java/org/alfresco/repo/subscriptions/SubscriptionServiceActivitiesTest.java +++ b/source/test-java/org/alfresco/repo/subscriptions/SubscriptionServiceActivitiesTest.java @@ -32,6 +32,7 @@ import org.alfresco.repo.activities.feed.local.LocalFeedTaskProcessor; import org.alfresco.repo.activities.post.lookup.PostLookup; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.site.SiteModel; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -112,6 +113,7 @@ public class SubscriptionServiceActivitiesTest protected static PostLookup postLookup; protected static FeedGenerator feedGenerator; protected static RetryingTransactionHelper transactionHelper; + protected static NodeArchiveService nodeArchiveService; private static Scheduler QUARTZ_SCHEDULER; @@ -139,6 +141,7 @@ public class SubscriptionServiceActivitiesTest activityService = (ActivityService) ctx.getBean("activityService"); nodeService = (NodeService) ctx.getBean("NodeService"); contentService = (ContentService) ctx.getBean("ContentService"); + nodeArchiveService = (NodeArchiveService)ctx.getBean("nodeArchiveService"); transactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper"); ChildApplicationContextFactory activitiesFeed = (ChildApplicationContextFactory) ctx.getBean("ActivitiesFeed"); @@ -473,10 +476,12 @@ public class SubscriptionServiceActivitiesTest private void deleteSite(String siteShortName) { - if (siteService.getSite(siteShortName) != null) + SiteInfo siteInfo = siteService.getSite(siteShortName); + if (siteInfo != null) { log.debug("Deleting site: " + siteShortName); siteService.deleteSite(siteShortName); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(siteInfo.getNodeRef())); } else { diff --git a/source/test-java/org/alfresco/util/test/junitrules/TemporarySites.java b/source/test-java/org/alfresco/util/test/junitrules/TemporarySites.java index 1d872bd2d3..0511f4ac83 100644 --- a/source/test-java/org/alfresco/util/test/junitrules/TemporarySites.java +++ b/source/test-java/org/alfresco/util/test/junitrules/TemporarySites.java @@ -26,6 +26,7 @@ import java.util.List; import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.activities.ActivityPostDAO; import org.alfresco.repo.domain.activities.ActivityPostEntity; +import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.site.SiteModel; @@ -74,6 +75,7 @@ public class TemporarySites extends AbstractPersonRule final RetryingTransactionHelper transactionHelper = (RetryingTransactionHelper) appContextRule.getApplicationContext().getBean("retryingTransactionHelper"); final SiteService siteService = appContextRule.getApplicationContext().getBean("siteService", SiteService.class); final ActivityPostDAO postDAO = appContextRule.getApplicationContext().getBean("postDAO", ActivityPostDAO.class); + final NodeArchiveService nodeArchiveService = (NodeArchiveService)appContextRule.getApplicationContext().getBean("nodeArchiveService"); // Run as admin to ensure all sites can be deleted irrespective of which user created them. AuthenticationUtil.runAs(new RunAsWork() @@ -112,6 +114,20 @@ public class TemporarySites extends AbstractPersonRule return null; } }); + transactionHelper.doInTransaction(new RetryingTransactionCallback() + { + @Override public Void execute() throws Throwable + { + for (SiteInfo site : temporarySites) + { + log.debug("Purging temporary site from trashcan: " + site.getShortName()); + nodeArchiveService.purgeArchivedNode(nodeArchiveService.getArchivedNode(site.getNodeRef())); + } + + return null; + } + }); + return null; } }, AuthenticationUtil.getAdminUserName());