Merged HEAD-BUG-FIX (4.3/Cloud) to HEAD (4.3/Cloud)

59269: Merged V4.2-BUG-FIX (4.2.1) to HEAD-BUG-FIX (Cloud/4.3)
      59268: Merged V4.1-BUG-FIX (4.1.8) to V4.2-BUG-FIX (4.2.1)
         59264: MNT-10237: Merged V4.1.6 (4.1.6.4) to V4.1-BUG-FIX (4.1.8) AGAIN!
            58707: MNT-10109: Merged DEV to PATCHES/V4.1.6 (4.1.6.4)
               58676: MNT-10109: Permissions are not restored when a deleted site is recovered from the trashcan
                  - Delete associated groups on callback when archived site is purged. Add unit test for case.
            58895: MNT-10109: Merged DEV to PATCHES/V4.1.6 (4.1.6.4)
               58855: MNT-10109: Permissions are not restored when a deleted site is recovered from the trashcan
                  - Fix unit tests failure by purging archived sites. Forbid new site creation if site group already exists.
               58871: MNT-10109: Permissions are not restored when a deleted site is recovered from the trashcan
                  - Return beforePurgeNode callback binding to Site class.
            58947: MNT-10109: PATCHES/V4.1.6 (4.1.6.4)
               58946: MNT-10109: Permissions are not restored when a deleted site is recovered from the trashcan
                  - Fix test failures by purging deleted sites from trashcan so that sitename can be reused. Change SiteServiceImplTest to avoid database deadlock.
            58949: MNT-10109: PATCHES/V4.1.6 (4.1.6.4)
               58948: MNT-10109: Permissions are not restored when a deleted site is recovered from the trashcan
                  - Fix test failures by purging deleted sites from trashcan so that sitename can be reused.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@62125 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2014-02-12 01:24:08 +00:00
parent dd04a7ebfa
commit 0144810a6d
16 changed files with 339 additions and 81 deletions

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@@ -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<BeforePurgeNodePolicy> 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<QName> 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<QName> getTypeAndAspectQNames(NodeRef nodeRef)
{
Set<QName> qnames = null;
try
{
Set<QName> aspectQNames = nodeService.getAspects(nodeRef);
QName typeQName = nodeService.getType(nodeRef);
qnames = new HashSet<QName>(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;
}
}

View File

@@ -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<Void>()
{
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<String, Set<String>> groupsMemberships = new HashMap<String, Set<String>>();
// Iterate over the role related groups and delete then
Set<String> 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<String> 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<Object>()
{
@@ -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<String> 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<String, Set<String>>)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);
}
}