Merged V3.1 to HEAD

14528: Added missing comma to CREATE TABLE statement: ETHREEOH-2150
   14531: Acegi diff file added.
   14608: Merged V2.2 to V3.1
      14509: ETWOTWO-1235 - update for MySQL
      14515: ETWOTWO-1235 - update #2 for MySQL
      14551: ETWOTWO-1235 - update #3 (fix "Failed to set top acl for store: .... unexpected updateCount ...")
   14736: Merged V2.2 to V3.1
      14735: ETWOTWO-1247 - WCM upgrade
   14748: ETHREEOH-2225 - WCM upgrade
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/V2.2:r14509,14515,14551,14735
      Merged /alfresco/BRANCHES/V3.1:r14528,14531,14608,14736,14748


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14770 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-06-17 14:00:18 +00:00
parent 1a86bfc624
commit 7ca716d403

View File

@@ -26,11 +26,14 @@ package org.alfresco.repo.admin.patch.impl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.alfresco.config.JNDIConstants;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.i18n.I18NUtil; import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.WCMAppModel; import org.alfresco.model.WCMAppModel;
@@ -72,6 +75,7 @@ import org.hibernate.ScrollableResults;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.type.LongType; import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
@@ -90,6 +94,8 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
private PersonService personService; private PersonService personService;
private static int batchSize = 500;
// cache staging store acl change set and shared acl id // cache staging store acl change set and shared acl id
private Map<String, Pair<DbAccessControlListChangeSet, Long>> stagingData = new HashMap<String, Pair<DbAccessControlListChangeSet, Long>>(10); private Map<String, Pair<DbAccessControlListChangeSet, Long>> stagingData = new HashMap<String, Pair<DbAccessControlListChangeSet, Long>>(10);
@@ -108,6 +114,11 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
this.personService = personService; this.personService = personService;
} }
public void setBatchSize(int batchSizeOverride)
{
batchSize = batchSizeOverride;
}
public ResetWCMToGroupBasedPermissionsPatch() public ResetWCMToGroupBasedPermissionsPatch()
{ {
helper = new HibernateHelper(); helper = new HibernateHelper();
@@ -167,6 +178,9 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
makeGroupsIfRequired(store); makeGroupsIfRequired(store);
addUsersToGroupIfRequired(store); addUsersToGroupIfRequired(store);
// belts-and-braces - nullify root children acls (if any) that are not 'www' (which will be overwritten anyway for staging stores)
nullifyAvmNodeAclsExcluding(store.getName(), JNDIConstants.DIR_DEFAULT_WWW);
setStagingAreaPermissions(store); setStagingAreaPermissions(store);
// flush any outstanding entities // flush any outstanding entities
@@ -254,6 +268,17 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
case AUTHOR: case AUTHOR:
case WORKFLOW: case WORKFLOW:
if (stagingData.get(extractBaseStore(store.getName())) == null)
{
// skip store - no corresponding base store
if (logger.isDebugEnabled())
{
logger.debug("Skip store "+store.getName()+" ("+storeType+") since no corresponding base store");
}
break;
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Process store "+store.getName()+" ("+storeType+")"); logger.debug("Process store "+store.getName()+" ("+storeType+")");
@@ -271,6 +296,17 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
case STAGING_PREVIEW: case STAGING_PREVIEW:
if (stagingData.get(extractBaseStore(store.getName())) == null)
{
// skip store - no corresponding base store
if (logger.isDebugEnabled())
{
logger.debug("Skip store "+store.getName()+" ("+storeType+") since no corresponding base store");
}
break;
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Process store "+store.getName()+" ("+storeType+")"); logger.debug("Process store "+store.getName()+" ("+storeType+")");
@@ -309,6 +345,17 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
case AUTHOR_WORKFLOW: case AUTHOR_WORKFLOW:
case WORKFLOW_PREVIEW: case WORKFLOW_PREVIEW:
if (stagingData.get(extractBaseStore(store.getName())) == null)
{
// skip store - no corresponding base store
if (logger.isDebugEnabled())
{
logger.debug("Skip store "+store.getName()+" ("+storeType+") since no corresponding base store");
}
break;
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Process store "+store.getName()+" ("+storeType+")"); logger.debug("Process store "+store.getName()+" ("+storeType+")");
@@ -345,6 +392,17 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
{ {
case AUTHOR_WORKFLOW_PREVIEW: case AUTHOR_WORKFLOW_PREVIEW:
if (stagingData.get(extractBaseStore(store.getName())) == null)
{
// skip store - no corresponding base store
if (logger.isDebugEnabled())
{
logger.debug("Skip store "+store.getName()+" ("+storeType+") since no corresponding base store");
}
break;
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Process store "+store.getName()+" ("+storeType+")"); logger.debug("Process store "+store.getName()+" ("+storeType+")");
@@ -433,6 +491,18 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
} }
} }
private void nullifyAvmNodeAclsExcluding(String storeName, String excludeRootChild) throws Exception
{
long startTime = System.currentTimeMillis();
int updatedCount = helper.nullifyAvmNodeAclsExcluding(storeName, excludeRootChild);
if (logger.isDebugEnabled() && (updatedCount > 0))
{
logger.debug("nullifyAvmNodeAcls ("+updatedCount+") for store: "+storeName+" excluding '"+excludeRootChild+"' in "+(System.currentTimeMillis()-startTime)/1000+" secs");
}
}
private void deleteDangling() private void deleteDangling()
{ {
try try
@@ -488,7 +558,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
helper.updateAclInheritsFrom(sharedAclId, definingAclId); helper.updateAclInheritsFrom(sharedAclId, definingAclId);
helper.updateAclInherited(sharedAclId, sharedAclId); // mimics current - do we need ? helper.updateAclInherited(sharedAclId, sharedAclId); // mimics current - do we need ?
// set defining acl // set defining acl (on 'www')
helper.setRootAcl(stagingStoreName, definingAclId); helper.setRootAcl(stagingStoreName, definingAclId);
// set shared acls // set shared acls
@@ -530,7 +600,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
helper.updateAclInheritsFrom(layeredAclId, baseSharedAclId); helper.updateAclInheritsFrom(layeredAclId, baseSharedAclId);
helper.updateAclInheritsFrom(sharedAclId, layeredAclId); helper.updateAclInheritsFrom(sharedAclId, layeredAclId);
// set layered acl // set layered acl (on 'www')
helper.setRootAcl(sandboxStoreName, layeredAclId); helper.setRootAcl(sandboxStoreName, layeredAclId);
// set shared acls // set shared acls
@@ -650,7 +720,14 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
{ {
long rootId = getAVMStoreCurrentRootNodeId(storeName); long rootId = getAVMStoreCurrentRootNodeId(storeName);
// recursively nullify below the root
int updatedCount = nullifyAvmNodeAcls(rootId); int updatedCount = nullifyAvmNodeAcls(rootId);
// also nullify the root
List<Long> childIds = new ArrayList<Long>(1);
childIds.add(rootId);
updatedCount += nullifyAvmNodeAclsForChildren(childIds);
return updatedCount; return updatedCount;
} }
catch (Throwable e) catch (Throwable e)
@@ -661,6 +738,47 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
} }
} }
private int nullifyAvmNodeAclsExcluding(String storeName, String excludeRootChild)
{
try
{
long rootId = getAVMStoreCurrentRootNodeId(storeName);
List<Pair<Long, String>> children = getAVMChildrenWithName(rootId);
int totalUpdatedCount = 0;
List<Long> childIds = new ArrayList<Long>(0);
for (Pair<Long, String> child : children)
{
Long childId = child.getFirst();
String name = child.getSecond();
if (! name.equals(excludeRootChild))
{
// recursively nullify below the (non-excluded) root children
totalUpdatedCount += nullifyAvmNodeAcls(childId);
childIds.add(childId);
}
}
if (childIds.size() > 0)
{
// also nullify the (non-excluded) root children
totalUpdatedCount += nullifyAvmNodeAclsForChildren(childIds);
}
return totalUpdatedCount;
}
catch (Throwable e)
{
String msg = "Failed to nullify avm node acl ids for: "+storeName+" (excluding "+excludeRootChild+")";
logger.error(msg, e);
throw new PatchException(msg, e);
}
}
private int nullifyAvmNodeAcls(final long parentId) throws Exception private int nullifyAvmNodeAcls(final long parentId) throws Exception
{ {
List<Long> childIds = getAVMChildren(parentId); List<Long> childIds = getAVMChildren(parentId);
@@ -669,7 +787,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
if (childIds.size() > 0) if (childIds.size() > 0)
{ {
updatedCount = nullifyAvmNodeAclsForChildren(parentId); updatedCount = nullifyAvmNodeAclsForChildren(childIds);
for (Long childId : childIds) for (Long childId : childIds)
{ {
@@ -681,55 +799,107 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
return updatedCount; return updatedCount;
} }
private int nullifyAvmNodeAclsForChildren(final long parentId) private int nullifyAvmNodeAclsForChildren(List<Long> childIds)
{ {
// native SQL int totalUpdateCount = 0;
SQLQuery query = getSession()
.createSQLQuery(
" update avm_nodes set acl_id = null "+
" where acl_id is not null " +
" and id in "+
" (select ce.child_id "+
" from avm_child_entries ce "+
" where ce.parent_id = :parentId) "+
"");
query.setLong("parentId", parentId); Iterator<Long> childIdIterator = childIds.iterator();
List<Long> batchChildIds = new ArrayList<Long>(batchSize);
return (Integer)query.executeUpdate(); while (childIdIterator.hasNext())
{
Long childId = childIdIterator.next();
batchChildIds.add(childId);
if (batchChildIds.size() == batchSize || !childIdIterator.hasNext())
{
// native SQL
SQLQuery query = getSession()
.createSQLQuery(
" update avm_nodes set acl_id = null "+
" where acl_id is not null " +
" and id in (:childIds) "+
"");
query.setParameterList("childIds", batchChildIds);
int batchUpdateCount = (Integer)query.executeUpdate();
totalUpdateCount = totalUpdateCount + batchUpdateCount;
batchChildIds.clear();
}
}
return totalUpdateCount;
} }
private int updateChildNodeAclIds(final long parentId, final long aclId) private int updateChildNodeAclIds(long aclId, List<Long> childIds)
{ {
// native SQL int totalUpdateCount = 0;
SQLQuery query = getSession()
.createSQLQuery(
" update avm_nodes set acl_id = :aclId "+
" where id in "+
" (select ce.child_id "+
" from avm_child_entries ce "+
" where ce.parent_id = :parentId) "+
"");
query.setLong("parentId", parentId); Iterator<Long> childIdIterator = childIds.iterator();
List<Long> batchChildIds = new ArrayList<Long>(batchSize);
query.setLong("aclId", aclId); while (childIdIterator.hasNext())
{
Long childId = childIdIterator.next();
batchChildIds.add(childId);
if (batchChildIds.size() == batchSize || !childIdIterator.hasNext())
{
// native SQL
SQLQuery query = getSession()
.createSQLQuery(
" update avm_nodes set acl_id = :aclId "+
" where id in (:childIds) "+
"");
query.setParameterList("childIds", batchChildIds);
query.setLong("aclId", aclId);
int batchUpdateCount = (Integer)query.executeUpdate();
totalUpdateCount = totalUpdateCount + batchUpdateCount;
batchChildIds.clear();
}
}
return (Integer)query.executeUpdate(); return totalUpdateCount;
} }
// set root acl on top node (eg. defining or layered acl applied to 'www') // set root acl on top node (eg. defining or layered acl applied to 'www')
private void setRootAcl(final String storeName, final long aclId) throws Exception private void setRootAcl(String storeName, long aclId) throws Exception
{ {
try try
{ {
long rootId = getAVMStoreCurrentRootNodeId(storeName); long rootId = getAVMStoreCurrentRootNodeId(storeName);
int updatedCount = updateChildNodeAclIds(rootId, aclId); List<Pair<Long, String>> children = getAVMChildrenWithName(rootId);
if (updatedCount != 1) int totalUpdatedCount = 0;
for (Pair<Long, String> child : children)
{ {
throw new AlfrescoRuntimeException("Failed to set top acl for store: "+storeName+" (unexpected updateCount = "+updatedCount); Long childId = child.getFirst();
String name = child.getSecond();
if (name.equals(JNDIConstants.DIR_DEFAULT_WWW))
{
List<Long> childIds = new ArrayList<Long>(1);
childIds.add(childId);
int updatedCount = updateChildNodeAclIds(aclId, childIds);
totalUpdatedCount += updatedCount;
}
}
// belts-and-braces - we expect to find & update 'www'
if (totalUpdatedCount != 1)
{
throw new AlfrescoRuntimeException("Failed to set top acl for store: "+storeName+" (unexpected updateCount = "+totalUpdatedCount);
} }
} }
catch (Throwable e) catch (Throwable e)
@@ -747,11 +917,25 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
{ {
long rootId = getAVMStoreCurrentRootNodeId(storeName); long rootId = getAVMStoreCurrentRootNodeId(storeName);
List<Long> childIds = getAVMChildren(rootId); List<Pair<Long, String>> children = getAVMChildrenWithName(rootId);
List<Long> childIds = new ArrayList<Long>(1);
for (Pair<Long, String> child : children)
{
Long childId = child.getFirst();
String name = child.getSecond();
if (name.equals(JNDIConstants.DIR_DEFAULT_WWW))
{
childIds.add(childId);
}
}
// belts-and-braces
if (childIds.size() != 1) if (childIds.size() != 1)
{ {
throw new AlfrescoRuntimeException("Expected 1 child of root ('www') found "+childIds.size()+ " children: "+storeName); throw new AlfrescoRuntimeException("Did not find one 'www' ("+childIds.size()+ ") for: "+storeName);
} }
return setSharedAcls(childIds.get(0), sharedAclId); return setSharedAcls(childIds.get(0), sharedAclId);
@@ -772,7 +956,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
if (childIds.size() > 0) if (childIds.size() > 0)
{ {
updatedCount = updateChildNodeAclIds(parentId, sharedAclId); updatedCount = updateChildNodeAclIds(sharedAclId, childIds);
for (Long childId : childIds) for (Long childId : childIds)
{ {
@@ -801,52 +985,172 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
// note: dangling shared acl currently possible (after creating new sandbox) // note: dangling shared acl currently possible (after creating new sandbox)
private int deleteDanglingAcls() throws Exception private int deleteDanglingAcls() throws Exception
{ {
// native SQL Set<Long> nonDanglingAclIds = getNonDanglingAcls();
SQLQuery query = getSession() Set<Long> aclIds = getAllAcls();
.createSQLQuery(
" delete from alf_acl_member "+
" where acl_id in ("+
" select a.id "+
" from alf_access_control_list a "+
" where a.id not in (" +
" select acl_id from avm_nodes where acl_id is not null "+
" union "+
" select acl_id from avm_stores where acl_id is not null "+
" union "+
" select acl_id from alf_node where acl_id is not null "+
" union "+
" select acl_id from alf_attributes where acl_id is not null "+
" ))");
int deletedCount = query.executeUpdate(); // get set of dangling acl ids
aclIds.removeAll(nonDanglingAclIds);
int totalDeletedCount = 0;
Iterator<Long> aclIdIterator = aclIds.iterator();
List<Long> batchAclIds = new ArrayList<Long>(batchSize);
while (aclIdIterator.hasNext())
{
Long aclId = aclIdIterator.next();
batchAclIds.add(aclId);
if (batchAclIds.size() == batchSize || !aclIdIterator.hasNext())
{
// native SQL
SQLQuery query = getSession()
.createSQLQuery(
" delete from alf_acl_member "+
" where acl_id in (:aclIds) "+
"");
query.setParameterList("aclIds", batchAclIds);
int batchDeletedCount = (Integer)query.executeUpdate();
totalDeletedCount = totalDeletedCount + batchDeletedCount;
batchAclIds.clear();
}
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Deleted "+deletedCount+" dangling acl members"); logger.debug("Deleted "+totalDeletedCount+" dangling acl members");
} }
// native SQL totalDeletedCount = 0;
query = getSession()
.createSQLQuery(
" delete from alf_access_control_list "+
" where id not in ("+
" select acl_id from avm_nodes where acl_id is not null "+
" union "+
" select acl_id from avm_stores where acl_id is not null "+
" union "+
" select acl_id from alf_node where acl_id is not null "+
" union "+
" select acl_id from alf_attributes where acl_id is not null "+
" )");
deletedCount = query.executeUpdate(); aclIdIterator = aclIds.iterator();
batchAclIds = new ArrayList<Long>(batchSize);
while (aclIdIterator.hasNext())
{
Long aclId = aclIdIterator.next();
batchAclIds.add(aclId);
if (batchAclIds.size() == batchSize || !aclIdIterator.hasNext())
{
// native SQL
SQLQuery query = getSession()
.createSQLQuery(
" delete from alf_access_control_list "+
" where id in (:aclIds) "+
"");
query.setParameterList("aclIds", batchAclIds);
int batchDeletedCount = (Integer)query.executeUpdate();
totalDeletedCount = totalDeletedCount + batchDeletedCount;
batchAclIds.clear();
}
}
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Deleted "+deletedCount+" dangling acls"); logger.debug("Deleted "+totalDeletedCount+" dangling acls");
} }
return deletedCount; return totalDeletedCount;
}
private Set<Long> getNonDanglingAcls()
{
final Set<Long> aclIds = new HashSet<Long>(10000);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
// native SQL
SQLQuery query = getSession().createSQLQuery(
" select acl_id from avm_nodes where acl_id is not null "+
" union "+
" select acl_id from avm_stores where acl_id is not null "+
" union "+
" select acl_id from alf_node where acl_id is not null "+
" union "+
" select acl_id from alf_attributes where acl_id is not null");
query.addScalar("acl_id", new LongType());
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
ScrollableResults rs = null;
try
{
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
while (rs.next())
{
Long aclId = (Long) rs.get(0);
aclIds.add(aclId);
}
}
catch (Throwable e)
{
String msg = "Failed to query for non-dangling acls";
logger.error(msg, e);
throw new PatchException(msg, e);
}
finally
{
if (rs != null)
{
try { rs.close(); } catch (Throwable e) { logger.error(e); }
}
}
return aclIds;
}
private Set<Long> getAllAcls()
{
final Set<Long> aclIds = new HashSet<Long>(10000);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
// native SQL
SQLQuery query = getSession().createSQLQuery("select id from alf_access_control_list ");
query.addScalar("id", new LongType());
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
ScrollableResults rs = null;
try
{
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
while (rs.next())
{
Long aclId = (Long) rs.get(0);
aclIds.add(aclId);
}
}
catch (Throwable e)
{
String msg = "Failed to query for all acls";
logger.error(msg, e);
throw new PatchException(msg, e);
}
finally
{
if (rs != null)
{
try { rs.close(); } catch (Throwable e) { logger.error(e); }
}
}
return aclIds;
} }
private long getAVMStoreCurrentRootNodeId(final String avmStoreName) private long getAVMStoreCurrentRootNodeId(final String avmStoreName)
@@ -903,6 +1207,51 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer
return childIds; return childIds;
} }
private List<Pair<Long, String>> getAVMChildrenWithName(final long parentId)
{
final List<Pair<Long, String>> children = new ArrayList<Pair<Long, String>>(100);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
// native SQL
SQLQuery query = getSession().createSQLQuery("select child_id, name as name from avm_child_entries where parent_id = :parentId");
query.setLong("parentId", parentId);
query.addScalar("child_id", new LongType());
query.addScalar("name", new StringType());
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
ScrollableResults rs = null;
try
{
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
while (rs.next())
{
Long childId = (Long) rs.get(0);
String name = (String) rs.get(1);
children.add(new Pair<Long, String>(childId, name));
}
}
catch (Throwable e)
{
String msg = "Failed to query for child entries (parent_id = "+parentId+")";
logger.error(msg, e);
throw new PatchException(msg, e);
}
finally
{
if (rs != null)
{
try { rs.close(); } catch (Throwable e) { logger.error(e); }
}
}
return children;
}
private long findOrCreateAce(final String authorityName, final String permissionName) throws Exception private long findOrCreateAce(final String authorityName, final String permissionName) throws Exception
{ {
final DbPermission permission = findOrCreatePermission(permissionName); final DbPermission permission = findOrCreatePermission(permissionName);