Merged V3.2 to HEAD

17475: ETHREEOH-3295: Fix to AuthorityMigrationPatch
      - Forces transaction retry if worker thread reaches child authority before a parent authority
      - Tested on Kev's 3.1.1 repository with ~20,000 bulk loaded users and ~2,000 Share sites
      - Now completes in 5 minutes as opposed to 45
   17461: ETHREEOH-3268: Added MutableAuthenticationService.isAuthenticationCreationAllowed () to allow conditional display of external user invitation UI
   17450: ETHREEOH-2762: Correction to previous fix. Do not generate new name when working copy copied back on check in.
   17440: ETHREEOH-3295: Fixed logging in FixNameCrcValuesPatch
   17439: ETHREEOH-2762: Improved behaviour when a working copy is copied
      - Working copy aspect already removed the working copy aspect on copy
      - Now derives a new name from the node checked out from and a UUID, preserving the extension
   17438: ETHREEOH-2690: Fix sequencing of jgroups system property setting
      - declared dependency between internalEHCacheManager and jgroupsPropertySetter
   17436: ETHREEOH-3295: Further performance improvements to AuthorityMigrationPatch
      - authority created at same time as all its parent associations to save lots of reindexing, as per LDAP sync
      - multi-threaded BatchProcessor (as used by LDAP sync, FixNameCrcValuesPatch) used to process work in 2 threads in batches of 20, report progress every 100 entries and handle transaction retries
      - BatchProcessor now promoted to its own package
   17394: Fix for license issue in local enterprise builds.
      - Replace Community with Enterprise in version.properties during enterprise war building
   17365: ETHREEOH-3229: Visited and fixed all SearchService result set leaks
   17362: ETHREEOH-3254: Eliminate needless ping to LDAP server in LDAPAuthenticationComponentImpl.implementationAllowsGuestLogin()
   17348: ETHREEOH-3003: Fix NPE in Hyperic when LicenseDescriptor has null fields
   17316: Merged V3.1 to V3.2
      17315: ETHREEOH-3092: PersonService won't let you create duplicate persons anymore.
      17314: ETHREEOH-3158: Fix RepoServerMgmt to work with external authentication methods
         - AuthenticationService.getCurrentTicket / getNewTicket now call pre authentication check before issuing a new ticket, thus still allowing ticket enforcement when external authentication is in use.
      17312: ETHREEOH-3219: Enable resolution of JMX server password file path on JBoss 5
      17299: Merged V3.2 to V3.1 (Record only)
         17297: ETHREEOH-1593: Changed name of username cookie and fixed login.jsp to decode it properly
         17248: ETHREEOH-1593: alfUser cookie value should be base 64 encoded to allow for non-ASCII characters
   17297: ETHREEOH-1593: Changed name of username cookie and fixed login.jsp to decode it properly
      - thanks Kev!
   17292: ETHREEOH-1842: Ticket association with HttpSession IDs tracked so that we don't invalidate a ticket in use by multiple sessions prematurely
      - AuthenticationService validate, getCurrentTicket, etc. methods now take optional sessionId arguments
   17269: Fix failing unit test
      - reinstate original behaviour of AbstractChainingAuthenticationService.getAuthenticationEnabled()
   17268: Fix InvitationService
      - Runs as system to do privileged AuthenticationService actions


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18105 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2010-01-18 17:41:59 +00:00
parent b96d174e1f
commit 1c1a35e500
55 changed files with 1153 additions and 711 deletions

View File

@@ -58,10 +58,17 @@ public class AVMLockingPatch extends AbstractPatch
{
ResultSet results =
searchService.query(new StoreRef(STORE), "lucene", "TYPE:\"wca:webfolder\"");
for (NodeRef nodeRef : results.getNodeRefs())
try
{
String webProject = (String)nodeService.getProperty(nodeRef, WCMAppModel.PROP_AVMSTORE);
fLockingService.addWebProject(webProject);
for (NodeRef nodeRef : results.getNodeRefs())
{
String webProject = (String)nodeService.getProperty(nodeRef, WCMAppModel.PROP_AVMSTORE);
fLockingService.addWebProject(webProject);
}
}
finally
{
results.close();
}
return I18NUtil.getMessage(MSG_SUCCESS);
}

View File

@@ -59,65 +59,72 @@ public class ActionRuleDecouplingPatch extends AbstractPatch
// Get all the node's of type rule in the store
int updateCount = 0;
ResultSet resultSet = this.searchService.query(storeRef, "lucene", "TYPE:\"" + RuleModel.TYPE_RULE + "\"");
for (NodeRef origRuleNodeRef : resultSet.getNodeRefs())
try
{
// Check that this rule need updated
if (!this.nodeService.exists(origRuleNodeRef))
for (NodeRef origRuleNodeRef : resultSet.getNodeRefs())
{
continue;
}
Map<QName, Serializable> origProperties = this.nodeService.getProperties(origRuleNodeRef);
if (origProperties.containsKey(RuleModel.PROP_EXECUTE_ASYNC) == false)
{
// 1) Change the type of the rule to be a composite action
this.nodeService.setType(origRuleNodeRef, ActionModel.TYPE_COMPOSITE_ACTION);
// 2) Create a new rule node
ChildAssociationRef parentRef = this.nodeService.getPrimaryParent(origRuleNodeRef);
NodeRef newRuleNodeRef = this.nodeService.createNode(
parentRef.getParentRef(),
parentRef.getTypeQName(),
parentRef.getQName(),
RuleModel.TYPE_RULE).getChildRef();
// 3) Move the origional rule under the new rule
this.nodeService.moveNode(
origRuleNodeRef,
newRuleNodeRef,
RuleModel.ASSOC_ACTION,
RuleModel.ASSOC_ACTION);
// 4) Move the various properties from the origional, onto the new rule
Map<QName, Serializable> newProperties = this.nodeService.getProperties(newRuleNodeRef);
// Set the rule type, execute async and applyToChildren properties on the rule
Serializable ruleType = origProperties.get(RuleModel.PROP_RULE_TYPE);
origProperties.remove(RuleModel.PROP_RULE_TYPE);
newProperties.put(RuleModel.PROP_RULE_TYPE, ruleType);
Serializable executeAsync = origProperties.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY);
origProperties.remove(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY);
newProperties.put(RuleModel.PROP_EXECUTE_ASYNC, executeAsync);
Serializable applyToChildren = origProperties.get(RuleModel.PROP_APPLY_TO_CHILDREN);
origProperties.remove(RuleModel.PROP_APPLY_TO_CHILDREN);
newProperties.put(RuleModel.PROP_APPLY_TO_CHILDREN, applyToChildren);
origProperties.remove(QName.createQName(RuleModel.RULE_MODEL_URI, "owningNodeRef"));
// Move the action and description values from the composite action onto the rule
Serializable title = origProperties.get(ActionModel.PROP_ACTION_TITLE);
origProperties.remove(ActionModel.PROP_ACTION_TITLE);
Serializable description = origProperties.get(ActionModel.PROP_ACTION_DESCRIPTION);
origProperties.remove(ActionModel.PROP_ACTION_DESCRIPTION);
newProperties.put(ContentModel.PROP_TITLE, title);
newProperties.put(ContentModel.PROP_DESCRIPTION, description);
// Set the updated property values
this.nodeService.setProperties(origRuleNodeRef, origProperties);
this.nodeService.setProperties(newRuleNodeRef, newProperties);
// Increment the update count
updateCount++;
// Check that this rule need updated
if (!this.nodeService.exists(origRuleNodeRef))
{
continue;
}
Map<QName, Serializable> origProperties = this.nodeService.getProperties(origRuleNodeRef);
if (origProperties.containsKey(RuleModel.PROP_EXECUTE_ASYNC) == false)
{
// 1) Change the type of the rule to be a composite action
this.nodeService.setType(origRuleNodeRef, ActionModel.TYPE_COMPOSITE_ACTION);
// 2) Create a new rule node
ChildAssociationRef parentRef = this.nodeService.getPrimaryParent(origRuleNodeRef);
NodeRef newRuleNodeRef = this.nodeService.createNode(
parentRef.getParentRef(),
parentRef.getTypeQName(),
parentRef.getQName(),
RuleModel.TYPE_RULE).getChildRef();
// 3) Move the origional rule under the new rule
this.nodeService.moveNode(
origRuleNodeRef,
newRuleNodeRef,
RuleModel.ASSOC_ACTION,
RuleModel.ASSOC_ACTION);
// 4) Move the various properties from the origional, onto the new rule
Map<QName, Serializable> newProperties = this.nodeService.getProperties(newRuleNodeRef);
// Set the rule type, execute async and applyToChildren properties on the rule
Serializable ruleType = origProperties.get(RuleModel.PROP_RULE_TYPE);
origProperties.remove(RuleModel.PROP_RULE_TYPE);
newProperties.put(RuleModel.PROP_RULE_TYPE, ruleType);
Serializable executeAsync = origProperties.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY);
origProperties.remove(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY);
newProperties.put(RuleModel.PROP_EXECUTE_ASYNC, executeAsync);
Serializable applyToChildren = origProperties.get(RuleModel.PROP_APPLY_TO_CHILDREN);
origProperties.remove(RuleModel.PROP_APPLY_TO_CHILDREN);
newProperties.put(RuleModel.PROP_APPLY_TO_CHILDREN, applyToChildren);
origProperties.remove(QName.createQName(RuleModel.RULE_MODEL_URI, "owningNodeRef"));
// Move the action and description values from the composite action onto the rule
Serializable title = origProperties.get(ActionModel.PROP_ACTION_TITLE);
origProperties.remove(ActionModel.PROP_ACTION_TITLE);
Serializable description = origProperties.get(ActionModel.PROP_ACTION_DESCRIPTION);
origProperties.remove(ActionModel.PROP_ACTION_DESCRIPTION);
newProperties.put(ContentModel.PROP_TITLE, title);
newProperties.put(ContentModel.PROP_DESCRIPTION, description);
// Set the updated property values
this.nodeService.setProperties(origRuleNodeRef, origProperties);
this.nodeService.setProperties(newRuleNodeRef, newProperties);
// Increment the update count
updateCount++;
}
}
}
finally
{
resultSet.close();
}
// Done
String msg = I18NUtil.getMessage(MSG_RESULT, updateCount);

View File

@@ -24,31 +24,37 @@
*/
package org.alfresco.repo.admin.patch.impl;
import java.sql.BatchUpdateException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Map.Entry;
import org.springframework.extensions.surf.util.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.admin.patch.PatchExecuter;
import org.alfresco.repo.batch.BatchProcessor;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.repo.security.authority.UnknownAuthorityException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.AuthorityType;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
/**
* Migrates authority information previously stored in the user store to the spaces store, using the new structure used
@@ -56,14 +62,13 @@ import org.apache.commons.logging.LogFactory;
*
* @author dward
*/
public class AuthorityMigrationPatch extends AbstractPatch
public class AuthorityMigrationPatch extends AbstractPatch implements ApplicationEventPublisherAware
{
/** The title we give to the batch process in progress messages / JMX. */
private static final String MSG_PROCESS_NAME = "patch.authorityMigration.process.name";
/** Progress message for authorities. */
private static final String MSG_PROGRESS_AUTHORITY = "patch.authorityMigration.progress.authority";
/** Progress message for associations. */
private static final String MSG_PROGRESS_ASSOC = "patch.authorityMigration.progress.assoc";
/** The warning message when a 'dangling' assoc is found that can't be created */
private static final String MSG_WARNING_INVALID_ASSOC = "patch.authorityMigration.warning.assoc";
/** Success message. */
private static final String MSG_SUCCESS = "patch.authorityMigration.result";
@@ -81,15 +86,18 @@ public class AuthorityMigrationPatch extends AbstractPatch
/** The old authority members property. */
private static final QName PROP_MEMBERS = QName.createQName(ContentModel.USER_MODEL_URI, "members");
/** The number of items to create in a transaction. */
private static final int BATCH_SIZE = 10;
/** The authority service. */
private AuthorityService authorityService;
/** The rule service. */
private RuleService ruleService;
/** The user bootstrap. */
private ImporterBootstrap userBootstrap;
/** The application event publisher. */
private ApplicationEventPublisher applicationEventPublisher;
/**
* Sets the authority service.
*
@@ -101,6 +109,17 @@ public class AuthorityMigrationPatch extends AbstractPatch
this.authorityService = authorityService;
}
/**
* Sets the rule service.
*
* @param ruleService
* the rule service
*/
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
/**
* Sets the user bootstrap.
*
@@ -112,6 +131,17 @@ public class AuthorityMigrationPatch extends AbstractPatch
this.userBootstrap = userBootstrap;
}
/**
* Sets the application event publisher.
*
* @param applicationEventPublisher
* the application event publisher
*/
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
{
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* Recursively retrieves the authorities under the given node and their associations.
*
@@ -122,14 +152,14 @@ public class AuthorityMigrationPatch extends AbstractPatch
* the node to find authorities below
* @param authoritiesToCreate
* the authorities to create
* @param childAssocs
* the child associations
* @param parentAssocs
* the parent associations
* @return count of the number of parent associations
*/
private void retrieveAuthorities(String parentAuthority, NodeRef nodeRef, Map<String, String> authoritiesToCreate,
Map<String, Set<String>> childAssocs)
private int retrieveAuthorities(String parentAuthority, NodeRef nodeRef, Map<String, String> authoritiesToCreate,
Map<String, Set<String>> parentAssocs)
{
// If we have a parent authority, prepare a list for recording its children
Set<String> children = parentAuthority == null ? null : childAssocs.get(parentAuthority);
int assocCount = 0;
// Process all children
List<ChildAssociationRef> cars = this.nodeService.getChildAssocs(nodeRef);
@@ -144,20 +174,20 @@ public class AuthorityMigrationPatch extends AbstractPatch
authoritiesToCreate.put(authorityName, DefaultTypeConverter.INSTANCE.convert(String.class, this.nodeService
.getProperty(current, AuthorityMigrationPatch.PROP_AUTHORITY_DISPLAY_NAME)));
// If we have a parent, remember the child association
// Record the parent association (or empty set if this is a root)
Set<String> parents = parentAssocs.get(authorityName);
if (parents == null)
{
parents = new TreeSet<String>();
parentAssocs.put(authorityName, parents);
}
if (parentAuthority != null)
{
if (children == null)
{
children = new TreeSet<String>();
childAssocs.put(parentAuthority, children);
}
children.add(authorityName);
parents.add(parentAuthority);
assocCount++;
}
// loop over properties
Set<String> propChildren = childAssocs.get(authorityName);
Collection<String> members = DefaultTypeConverter.INSTANCE.getCollection(String.class, this.nodeService
.getProperty(current, AuthorityMigrationPatch.PROP_MEMBERS));
if (members != null)
@@ -167,119 +197,89 @@ public class AuthorityMigrationPatch extends AbstractPatch
// Believe it or not, some old authorities have null members in them!
if (user != null)
{
if (propChildren == null)
Set<String> propParents = parentAssocs.get(user);
if (propParents == null)
{
propChildren = new TreeSet<String>();
childAssocs.put(authorityName, propChildren);
propParents = new TreeSet<String>();
parentAssocs.put(user, propParents);
}
propChildren.add(user);
propParents.add(authorityName);
assocCount++;
}
}
}
retrieveAuthorities(authorityName, current, authoritiesToCreate, childAssocs);
assocCount += retrieveAuthorities(authorityName, current, authoritiesToCreate, parentAssocs);
}
return assocCount;
}
/**
* Migrates the authorities.
* Migrates the authorities and their associations.
*
* @param authoritiesToCreate
* the authorities to create
* @param parentAssocs
* the parent associations to create (if they don't exist already)
* @return the number of authorities migrated
*/
private int migrateAuthorities(Map<String, String> authoritiesToCreate)
private void migrateAuthorities(final Map<String, String> authoritiesToCreate, Map<String, Set<String>> parentAssocs)
{
int processedCount = 0;
final Iterator<Map.Entry<String, String>> i = authoritiesToCreate.entrySet().iterator();
RetryingTransactionHelper retryingTransactionHelper = this.transactionService.getRetryingTransactionHelper();
// Process batches in separate transactions for maximum performance
while (i.hasNext())
BatchProcessor.Worker<Map.Entry<String, Set<String>>> worker = new BatchProcessor.Worker<Map.Entry<String, Set<String>>>()
{
processedCount += retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Integer>()
public String getIdentifier(Entry<String, Set<String>> entry)
{
public Integer execute() throws Throwable
{
int processedCount = 0;
do
{
Map.Entry<String, String> authority = i.next();
String authorityName = authority.getKey();
boolean existed = AuthorityMigrationPatch.this.authorityService.authorityExists(authorityName);
if (existed)
{
i.remove();
}
else
{
AuthorityMigrationPatch.this.authorityService.createAuthority(AuthorityType
.getAuthorityType(authorityName), AuthorityMigrationPatch.this.authorityService
.getShortName(authorityName), authority.getValue(), null);
processedCount++;
}
}
while (processedCount < AuthorityMigrationPatch.BATCH_SIZE && i.hasNext());
return processedCount;
}
}, false, true);
return entry.getKey();
}
// Report progress
AuthorityMigrationPatch.progress_logger.info(I18NUtil.getMessage(
AuthorityMigrationPatch.MSG_PROGRESS_AUTHORITY, processedCount));
}
return processedCount;
}
/**
* Migrates the group associations.
*
* @param authoritiesCreated
* the authorities created
* @param childAssocs
* the child associations
* @return the number of associations migrated
*/
private int migrateAssocs(final Map<String, String> authoritiesCreated, Map<String, Set<String>> childAssocs)
{
int processedCount = 0;
final Iterator<Map.Entry<String, Set<String>>> j = childAssocs.entrySet().iterator();
RetryingTransactionHelper retryingTransactionHelper = this.transactionService.getRetryingTransactionHelper();
// Process batches in separate transactions for maximum performance
while (j.hasNext())
{
processedCount += retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Integer>()
public void process(Entry<String, Set<String>> authority) throws Throwable
{
public Integer execute() throws Throwable
String authorityName = authority.getKey();
boolean existed = AuthorityMigrationPatch.this.authorityService.authorityExists(authorityName);
Set<String> knownParents;
if (existed)
{
int processedCount = 0;
do
{
Map.Entry<String, Set<String>> childAssoc = j.next();
String parentAuthority = childAssoc.getKey();
Set<String> knownChildren = authoritiesCreated.containsKey(parentAuthority) ? Collections
.<String> emptySet() : AuthorityMigrationPatch.this.authorityService
.getContainedAuthorities(AuthorityType.GROUP, parentAuthority, true);
for (String authorityName : childAssoc.getValue())
{
if (!knownChildren.contains(authorityName))
{
AuthorityMigrationPatch.this.authorityService.addAuthority(parentAuthority,
authorityName);
processedCount++;
}
}
}
while (processedCount < AuthorityMigrationPatch.BATCH_SIZE && j.hasNext());
return processedCount;
knownParents = AuthorityMigrationPatch.this.authorityService.getContainingAuthorities(
AuthorityType.GROUP, authorityName, true);
}
}, false, true);
// Report progress
AuthorityMigrationPatch.progress_logger.info(I18NUtil.getMessage(
AuthorityMigrationPatch.MSG_PROGRESS_ASSOC, processedCount));
}
return processedCount;
else
{
knownParents = Collections.emptySet();
AuthorityType authorityType = AuthorityType.getAuthorityType(authorityName);
// We have associations to a non-existent authority. If it is a user, just skip it because it must
// have been a 'dangling' reference
if (authorityType == AuthorityType.USER)
{
AuthorityMigrationPatch.progress_logger.warn(I18NUtil.getMessage(
AuthorityMigrationPatch.MSG_WARNING_INVALID_ASSOC, authorityName));
return;
}
AuthorityMigrationPatch.this.authorityService.createAuthority(authorityType,
AuthorityMigrationPatch.this.authorityService.getShortName(authorityName),
authoritiesToCreate.get(authorityName), null);
}
Set<String> parentAssocsToCreate = authority.getValue();
parentAssocsToCreate.removeAll(knownParents);
if (!parentAssocsToCreate.isEmpty())
{
try
{
AuthorityMigrationPatch.this.authorityService.addAuthority(parentAssocsToCreate, authorityName);
}
catch (UnknownAuthorityException e)
{
// Let's force a transaction retry if a parent doesn't exist. It may be because we are waiting
// for another worker thread to create it
throw new BatchUpdateException().initCause(e);
}
}
}
};
// Migrate using 2 threads, 20 authorities per transaction. Log every 100 entries.
new BatchProcessor<Map.Entry<String, Set<String>>>(AuthorityMigrationPatch.progress_logger,
this.transactionService.getRetryingTransactionHelper(), this.ruleService,
this.applicationEventPublisher, parentAssocs.entrySet(), I18NUtil
.getMessage(AuthorityMigrationPatch.MSG_PROCESS_NAME), 100, 2, 20).process(worker, true);
}
/**
@@ -323,18 +323,71 @@ public class AuthorityMigrationPatch extends AbstractPatch
@Override
protected String applyInternal() throws Exception
{
int authorities = 0;
int assocs = 0;
NodeRef authorityContainer = getAuthorityContainer();
int authorities = 0, assocs = 0;
if (authorityContainer != null)
{
// Crawl the old tree of authorities
Map<String, String> authoritiesToCreate = new TreeMap<String, String>();
Map<String, Set<String>> childAssocs = new TreeMap<String, Set<String>>();
retrieveAuthorities(null, authorityContainer, authoritiesToCreate, childAssocs);
authorities = migrateAuthorities(authoritiesToCreate);
assocs = migrateAssocs(authoritiesToCreate, childAssocs);
Map<String, Set<String>> parentAssocs = new TreeMap<String, Set<String>>();
assocs = retrieveAuthorities(null, authorityContainer, authoritiesToCreate, parentAssocs);
// Sort the group associations in parent-first order (root groups first)
Map<String, Set<String>> sortedParentAssocs = new LinkedHashMap<String, Set<String>>(
parentAssocs.size() * 2);
List<String> authorityPath = new ArrayList<String>(5);
for (String authority : parentAssocs.keySet())
{
authorityPath.add(authority);
visitGroupAssociations(authorityPath, parentAssocs, sortedParentAssocs);
authorityPath.clear();
}
// Recreate the authorities and their associations in parent-first order
migrateAuthorities(authoritiesToCreate, sortedParentAssocs);
authorities = authoritiesToCreate.size();
}
// build the result message
return I18NUtil.getMessage(AuthorityMigrationPatch.MSG_SUCCESS, authorities, assocs);
}
/**
* Visits the last authority in the given list by recursively visiting its parents in associationsOld and then
* adding the authority to associationsNew. Used to sort associationsOld into 'parent-first' order.
*
* @param authorityPath
* The authority to visit, preceeded by all its descendants. Allows detection of cyclic child
* associations.
* @param associationsOld
* the association map to sort
* @param associationsNew
* the association map to add to in parent-first order
*/
private static void visitGroupAssociations(List<String> authorityPath, Map<String, Set<String>> associationsOld,
Map<String, Set<String>> associationsNew)
{
String authorityName = authorityPath.get(authorityPath.size() - 1);
if (!associationsNew.containsKey(authorityName))
{
Set<String> associations = associationsOld.get(authorityName);
if (!associations.isEmpty())
{
int insertIndex = authorityPath.size();
for (String parentAuthority : associations)
{
// Prevent cyclic paths
if (!authorityPath.contains(parentAuthority))
{
authorityPath.add(parentAuthority);
visitGroupAssociations(authorityPath, associationsOld, associationsNew);
authorityPath.remove(insertIndex);
}
}
}
associationsNew.put(authorityName, associations);
}
}
}

View File

@@ -102,12 +102,19 @@ public class ContentFormTypePatch extends AbstractPatch
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("ASPECT:\"" + WCMAppModel.ASPECT_FORM + "\"");
ResultSet rs = this.searchService.query(sp);
Collection<NodeRef> result = new ArrayList<NodeRef>(rs.length());
for (ResultSetRow row : rs)
try
{
result.add(row.getNodeRef());
Collection<NodeRef> result = new ArrayList<NodeRef>(rs.length());
for (ResultSetRow row : rs)
{
result.add(row.getNodeRef());
}
return result;
}
finally
{
rs.close();
}
return result;
}
}

View File

@@ -38,13 +38,13 @@ import java.util.zip.CRC32;
import org.springframework.extensions.surf.util.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.batch.BatchProcessor;
import org.alfresco.repo.batch.BatchProcessor.Worker;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.QNameDAO;
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.security.sync.BatchProcessor;
import org.alfresco.repo.security.sync.BatchProcessor.Worker;
import org.alfresco.service.cmr.admin.PatchException;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.namespace.QName;
@@ -186,7 +186,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationE
public String fixCrcValues() throws Exception
{
// get the association types to check
BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>(transactionService
BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>(logger, transactionService
.getRetryingTransactionHelper(), ruleService, applicationEventPublisher, findMismatchedCrcs(),
"FixNameCrcValuesPatch", 100, 2, 20);
@@ -224,7 +224,8 @@ public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationE
}
// Update the CRCs
long childCrc = getCrc(childName);
long qnameCrc = ChildAssocImpl.getCrc(assoc.getQName(qnameDAO));
QName qname = assoc.getQName(qnameDAO);
long qnameCrc = ChildAssocImpl.getCrc(qname);
// Update the assoc
assoc.setChildNodeNameCrc(childCrc);
@@ -237,7 +238,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationE
catch (Throwable e)
{
String msg = I18NUtil.getMessage(MSG_UNABLE_TO_CHANGE, childNode.getId(), childName, oldChildCrc,
childCrc, oldQNameCrc, qnameCrc, e.getMessage());
childCrc, qname, oldQNameCrc, qnameCrc, e.getMessage());
// We just log this and add details to the message file
if (logger.isDebugEnabled())
{
@@ -251,7 +252,8 @@ public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationE
}
getSession().clear();
// Record
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldChildCrc, childCrc, oldQNameCrc, qnameCrc));
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldChildCrc, childCrc,
qname, oldQNameCrc, qnameCrc));
}}, true);