mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
17163: org.alfresco.repo.domain.hibernate.AclDaoComponentImpl.updateAuthority() needs to flush/dirty the session in order to work 17160: Fix HeartBeat - Lazy initialization in scheduled job needed its own transaction 17146: Fix failing unit tests - HibernateNodeDaoServiceImpl.moveNodeToStore() must invalidate parentAssocsCache now that it contains NodeRefs 17145: Fixes to patches for new CRC schema changes - Sequenced patch.fixNameCrcValues-2 before all other patches - Fixed typos in schema upgrade script and added CRCs for the repository descriptor nodes, so that the descriptor service and patch service can boot up - HeartBeat initializes lazily so that it doesn't try to load information before the patch service has bootstrapped - Made FixNameCrcValuesPatch industrial strength by using BatchProcessor to handle multi threading, progress reporting and transaction delineation 17097: Removal of spurious logs directory accidentally introduced in 17096 17096: Performance tuning for improved throughput during high volume import from LDAP directory - Lucene indexer will now no longer index and then reindex the same node in the same transaction - lucene.indexer.mergerTargetOverlaysBlockingFactor reduced to 1 (improves indexing performance and no excessive throttling observed during 10 hour test) - HomeFolderManager fixed so that it pays attention to the eager home folder creation flag - HibernateNodeDaoServiceImpl.parentAssocsCache 'upgraded' to hold information about root nodes and node refs so that recursive methods such as prependPaths can run entirely out of the cache - Boolean argument added to getChildAssocs() so that preloading of all child nodes is optional - qname_crc column added to alf_child_assoc to allow efficient lookup and indexing of child associations by QName. CRC of (qname_namespace, qname_localname). - idx_alf_cass_qnln on qname_localname replaced with idx_alf_cass_qncrc (qname_crc, type_qname_id, parent_node_id) - All node service lookup queries involving qname_localname modified to include qname_crc in WHERE clause - schema patch provided - existing org.alfresco.repo.admin.patch.impl.FixNameCrcValuesPatch extended to also fill in qname_crc column and forced to run on newer schemas - Optimized ChainingUserRegistrySynchronizer so that it doesn't have to look up the entire set of authorities during an 'empty' incremental sync - ChainingUserRegistrySynchronizer no longer starts an outer transaction around all its smaller transactions (used to die due to timeout) - rule service disabled for LDAP batch processing threads - org.alfresco.cache.parentAssocsCache and org.alfresco.cache.storeAndNodeIdCache size increased to 80,000 - Fixed case sensitivity issue with person caching in PersonServiceImpl - Cache the people container in PersonServiceImpl for faster person lookups - PersonDAO removed and replaced with now more efficient node service child assoc lookup methods git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@17168 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.rule.RuleService;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
@@ -65,6 +66,9 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
/** The retrying transaction helper. */
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
/** The rule service. */
|
||||
private RuleService ruleService;
|
||||
|
||||
/** The collection. */
|
||||
private Collection<T> collection;
|
||||
|
||||
@@ -106,6 +110,8 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
*
|
||||
* @param retryingTransactionHelper
|
||||
* the retrying transaction helper
|
||||
* @param ruleService
|
||||
* the rule service
|
||||
* @param collection
|
||||
* the collection
|
||||
* @param processName
|
||||
@@ -119,11 +125,12 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
* @param batchSize
|
||||
* the number of entries we process at a time in a transaction
|
||||
*/
|
||||
public BatchProcessor(RetryingTransactionHelper retryingTransactionHelper,
|
||||
public BatchProcessor(RetryingTransactionHelper retryingTransactionHelper, RuleService ruleService,
|
||||
ApplicationEventPublisher applicationEventPublisher, Collection<T> collection, String processName,
|
||||
int loggingInterval, int workerThreads, int batchSize)
|
||||
{
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
this.ruleService = ruleService;
|
||||
this.collection = collection;
|
||||
this.processName = processName;
|
||||
this.loggingInterval = loggingInterval;
|
||||
@@ -272,7 +279,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
// Create a thread pool executor with the specified number of threads and a finite blocking queue of jobs
|
||||
ExecutorService executorService = splitTxns && this.workerThreads > 1 ? new ThreadPoolExecutor(
|
||||
this.workerThreads, this.workerThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(
|
||||
this.workerThreads * 10)
|
||||
this.workerThreads * batchSize * 10)
|
||||
{
|
||||
// Add blocking behaviour to work queue
|
||||
@Override
|
||||
@@ -378,10 +385,10 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
NumberFormat.getPercentInstance().format(
|
||||
totalResults == 0 ? 1.0F : (float) processed / totalResults)).append(" complete");
|
||||
}
|
||||
long duration = System.currentTimeMillis() - startTime.getTime();
|
||||
long duration = System.currentTimeMillis() - this.startTime.getTime();
|
||||
if (duration > 0)
|
||||
{
|
||||
message.append(". Rate: ").append(processed * 1000 / duration).append(" per second");
|
||||
message.append(". Rate: ").append(processed * 1000L / duration).append(" per second");
|
||||
}
|
||||
message.append(". " + this.totalErrors + " failures detected.");
|
||||
BatchProcessor.logger.info(message);
|
||||
@@ -454,13 +461,13 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
|
||||
/** The current entry being processed in the transaction */
|
||||
private String txnEntryId;
|
||||
|
||||
|
||||
/** The last error. */
|
||||
private Throwable txnLastError;
|
||||
|
||||
|
||||
/** The last error entry id. */
|
||||
private String txnLastErrorEntryId;
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute ()
|
||||
@@ -473,7 +480,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
this.txnEntryId = this.worker.getIdentifier(entry);
|
||||
synchronized (BatchProcessor.this)
|
||||
{
|
||||
BatchProcessor.this.currentEntryId = txnEntryId;
|
||||
BatchProcessor.this.currentEntryId = this.txnEntryId;
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -486,11 +493,11 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
{
|
||||
if (BatchProcessor.logger.isWarnEnabled())
|
||||
{
|
||||
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \"" + txnEntryId
|
||||
+ "\".", t);
|
||||
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \""
|
||||
+ this.txnEntryId + "\".", t);
|
||||
}
|
||||
this.txnLastError = t;
|
||||
this.txnLastErrorEntryId = txnEntryId;
|
||||
this.txnLastErrorEntryId = this.txnEntryId;
|
||||
this.txnErrors++;
|
||||
}
|
||||
else
|
||||
@@ -508,6 +515,8 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
// Disable rules for this thread
|
||||
BatchProcessor.this.ruleService.disableRules();
|
||||
try
|
||||
{
|
||||
BatchProcessor.this.retryingTransactionHelper.doInTransaction(this, false, this.splitTxns);
|
||||
@@ -540,6 +549,12 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
throw new AlfrescoRuntimeException("Transactional error during " + getProcessName(), t);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Re-enable rules
|
||||
BatchProcessor.this.ruleService.enableRules();
|
||||
}
|
||||
|
||||
commitProgress();
|
||||
}
|
||||
|
||||
@@ -606,6 +621,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
||||
BatchProcessor.this.lastError = this.txnLastError;
|
||||
BatchProcessor.this.lastErrorEntryId = this.txnLastErrorEntryId;
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||
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.cmr.security.PersonService;
|
||||
@@ -134,6 +135,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
/** The retrying transaction helper. */
|
||||
private RetryingTransactionHelper retryingTransactionHelper;
|
||||
|
||||
/** The rule service. */
|
||||
private RuleService ruleService;
|
||||
|
||||
/** The job lock service. */
|
||||
private JobLockService jobLockService;
|
||||
|
||||
@@ -221,6 +225,17 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rule service.
|
||||
*
|
||||
* @param ruleService
|
||||
* the new rule service
|
||||
*/
|
||||
public void setRuleService(RuleService ruleService)
|
||||
{
|
||||
this.ruleService = ruleService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the job lock service.
|
||||
*
|
||||
@@ -304,6 +319,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
*/
|
||||
public void synchronize(boolean force, boolean splitTxns)
|
||||
{
|
||||
String lockToken = null;
|
||||
|
||||
// Let's ensure all exceptions get logged
|
||||
try
|
||||
{
|
||||
@@ -314,8 +331,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
{
|
||||
// If this is an automated sync on startup or scheduled sync, don't even wait around for the lock.
|
||||
// Assume the sync will be completed on another node.
|
||||
this.jobLockService.getTransactionalLock(ChainingUserRegistrySynchronizer.LOCK_QNAME,
|
||||
ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
|
||||
lockToken = this.retryingTransactionHelper.doInTransaction(
|
||||
new RetryingTransactionCallback<String>()
|
||||
{
|
||||
public String execute() throws Throwable
|
||||
{
|
||||
return ChainingUserRegistrySynchronizer.this.jobLockService.getLock(
|
||||
ChainingUserRegistrySynchronizer.LOCK_QNAME,
|
||||
ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
|
||||
}
|
||||
}, false, splitTxns);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -382,6 +407,23 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
|
||||
throw e;
|
||||
}
|
||||
// Release the lock if necessary
|
||||
finally
|
||||
{
|
||||
if (lockToken != null)
|
||||
{
|
||||
final String token = lockToken;
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.this.jobLockService.releaseLock(token,
|
||||
ChainingUserRegistrySynchronizer.LOCK_QNAME);
|
||||
return null;
|
||||
}
|
||||
}, false, splitTxns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,7 +500,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
final Set<String> zoneSet = getZones(zoneId);
|
||||
|
||||
long lastModifiedMillis = getMostRecentUpdateTime(
|
||||
ChainingUserRegistrySynchronizer.GROUP_LAST_MODIFIED_ATTRIBUTE, zoneId);
|
||||
ChainingUserRegistrySynchronizer.GROUP_LAST_MODIFIED_ATTRIBUTE, zoneId, splitTxns);
|
||||
Date lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
||||
|
||||
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
||||
@@ -474,33 +516,22 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
}
|
||||
}
|
||||
|
||||
// Get current set of known authorities
|
||||
Set<String> allZoneAuthorities = this.retryingTransactionHelper.doInTransaction(
|
||||
new RetryingTransactionCallback<Set<String>>()
|
||||
{
|
||||
public Set<String> execute() throws Throwable
|
||||
{
|
||||
return ChainingUserRegistrySynchronizer.this.authorityService.getAllAuthoritiesInZone(zoneId,
|
||||
null);
|
||||
}
|
||||
}, false, splitTxns);
|
||||
|
||||
// First, analyze the group structure. Create maps of authorities to their parents for associations to create
|
||||
// and delete. Also deal with 'overlaps' with other zones in the authentication chain.
|
||||
final BatchProcessor<NodeDescription> groupProcessor = new BatchProcessor<NodeDescription>(
|
||||
this.retryingTransactionHelper, this.applicationEventPublisher, userRegistry.getGroups(lastModified),
|
||||
zone + " Group Analysis", this.loggingInterval, this.workerThreads, 20);
|
||||
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher, userRegistry
|
||||
.getGroups(lastModified), zone + " Group Analysis", this.loggingInterval, this.workerThreads,
|
||||
20);
|
||||
class Analyzer implements Worker<NodeDescription>
|
||||
{
|
||||
private final Set<String> allZoneAuthorities;
|
||||
private final Set<String> allZoneAuthorities = new TreeSet<String>();
|
||||
private final Set<String> groupsToCreate = new TreeSet<String>();
|
||||
private final Map<String, Set<String>> groupAssocsToCreate = new TreeMap<String, Set<String>>();
|
||||
private final Map<String, Set<String>> groupAssocsToDelete = new TreeMap<String, Set<String>>();
|
||||
private long latestTime;
|
||||
|
||||
public Analyzer(final Set<String> allZoneAuthorities, final long latestTime)
|
||||
public Analyzer(final long latestTime)
|
||||
{
|
||||
this.allZoneAuthorities = allZoneAuthorities;
|
||||
this.latestTime = latestTime;
|
||||
}
|
||||
|
||||
@@ -509,6 +540,11 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
return this.latestTime;
|
||||
}
|
||||
|
||||
public Set<String> getAllZoneAuthorities()
|
||||
{
|
||||
return this.allZoneAuthorities;
|
||||
}
|
||||
|
||||
public Set<String> getGroupsToCreate()
|
||||
{
|
||||
return this.groupsToCreate;
|
||||
@@ -665,105 +701,129 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
}
|
||||
}
|
||||
|
||||
Analyzer groupAnalyzer = new Analyzer(allZoneAuthorities, lastModifiedMillis);
|
||||
Analyzer groupAnalyzer = new Analyzer(lastModifiedMillis);
|
||||
int groupProcessedCount = groupProcessor.process(groupAnalyzer, splitTxns);
|
||||
final Map<String, Set<String>> groupAssocsToCreate = groupAnalyzer.getGroupAssocsToCreate();
|
||||
final Map<String, Set<String>> groupAssocsToDelete = groupAnalyzer.getGroupAssocsToDelete();
|
||||
|
||||
// Prune our set of authorities according to deletions
|
||||
Set<String> deletionCandidates = null;
|
||||
if (force)
|
||||
|
||||
// If we got back some groups, we have to cross reference them with the set of known authorities
|
||||
if (force || !groupAssocsToCreate.isEmpty())
|
||||
{
|
||||
deletionCandidates = new TreeSet<String>(allZoneAuthorities);
|
||||
userRegistry.processDeletions(deletionCandidates);
|
||||
allZoneAuthorities.removeAll(deletionCandidates);
|
||||
groupAssocsToCreate.keySet().removeAll(deletionCandidates);
|
||||
groupAssocsToDelete.keySet().removeAll(deletionCandidates);
|
||||
}
|
||||
|
||||
// Sort the group associations in depth-first order (root groups first)
|
||||
Map<String, Set<String>> sortedGroupAssociations = new LinkedHashMap<String, Set<String>>(groupAssocsToCreate
|
||||
.size() * 2);
|
||||
List<String> authorityPath = new ArrayList<String>(5);
|
||||
for (String authority : groupAssocsToCreate.keySet())
|
||||
{
|
||||
if (allZoneAuthorities.contains(authority))
|
||||
{
|
||||
authorityPath.add(authority);
|
||||
visitGroupAssociations(authorityPath, allZoneAuthorities, groupAssocsToCreate, sortedGroupAssociations);
|
||||
authorityPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the groups and their parent associations in depth-first order
|
||||
final Set<String> groupsToCreate = groupAnalyzer.getGroupsToCreate();
|
||||
BatchProcessor<Map.Entry<String, Set<String>>> groupCreator = new BatchProcessor<Map.Entry<String, Set<String>>>(
|
||||
this.retryingTransactionHelper, this.applicationEventPublisher, sortedGroupAssociations.entrySet(),
|
||||
zone + " Group Creation and Association", this.loggingInterval, 1, 20);
|
||||
groupCreator.process(new Worker<Map.Entry<String, Set<String>>>()
|
||||
{
|
||||
|
||||
public String getIdentifier(Map.Entry<String, Set<String>> entry)
|
||||
{
|
||||
return entry.getKey() + " " + entry.getValue();
|
||||
}
|
||||
|
||||
public void process(Map.Entry<String, Set<String>> entry) throws Throwable
|
||||
{
|
||||
Set<String> parents = entry.getValue();
|
||||
String child = entry.getKey();
|
||||
|
||||
if (groupsToCreate.contains(child))
|
||||
{
|
||||
String groupShortName = ChainingUserRegistrySynchronizer.this.authorityService.getShortName(child);
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
// Get current set of known authorities
|
||||
Set<String> allZoneAuthorities = this.retryingTransactionHelper.doInTransaction(
|
||||
new RetryingTransactionCallback<Set<String>>()
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.debug("Creating group '" + groupShortName + "'");
|
||||
}
|
||||
// create the group
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.createAuthority(AuthorityType
|
||||
.getAuthorityType(child), groupShortName, groupShortName, zoneSet);
|
||||
}
|
||||
if (!parents.isEmpty())
|
||||
{
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
{
|
||||
for (String groupName : parents)
|
||||
public Set<String> execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.debug("Adding '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService.getShortName(child)
|
||||
+ "' to group '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService.getShortName(groupName)
|
||||
+ "'");
|
||||
return ChainingUserRegistrySynchronizer.this.authorityService.getAllAuthoritiesInZone(
|
||||
zoneId, null);
|
||||
}
|
||||
}
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.addAuthority(parents, child);
|
||||
}
|
||||
Set<String> parentsToDelete = groupAssocsToDelete.get(child);
|
||||
if (parentsToDelete != null && !parentsToDelete.isEmpty())
|
||||
}, true, splitTxns);
|
||||
// Add in those that will be created or moved
|
||||
allZoneAuthorities.addAll(groupAnalyzer.getAllZoneAuthorities());
|
||||
|
||||
// Prune our set of authorities according to deletions
|
||||
if (force)
|
||||
{
|
||||
deletionCandidates = new TreeSet<String>(allZoneAuthorities);
|
||||
userRegistry.processDeletions(deletionCandidates);
|
||||
allZoneAuthorities.removeAll(deletionCandidates);
|
||||
groupAssocsToCreate.keySet().removeAll(deletionCandidates);
|
||||
groupAssocsToDelete.keySet().removeAll(deletionCandidates);
|
||||
}
|
||||
|
||||
if (!groupAssocsToCreate.isEmpty())
|
||||
{
|
||||
// Sort the group associations in depth-first order (root groups first)
|
||||
Map<String, Set<String>> sortedGroupAssociations = new LinkedHashMap<String, Set<String>>(
|
||||
groupAssocsToCreate.size() * 2);
|
||||
List<String> authorityPath = new ArrayList<String>(5);
|
||||
for (String authority : groupAssocsToCreate.keySet())
|
||||
{
|
||||
for (String parent : parentsToDelete)
|
||||
if (allZoneAuthorities.contains(authority))
|
||||
{
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
authorityPath.add(authority);
|
||||
visitGroupAssociations(authorityPath, allZoneAuthorities, groupAssocsToCreate,
|
||||
sortedGroupAssociations);
|
||||
authorityPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the groups and their parent associations in depth-first order
|
||||
final Set<String> groupsToCreate = groupAnalyzer.getGroupsToCreate();
|
||||
BatchProcessor<Map.Entry<String, Set<String>>> groupCreator = new BatchProcessor<Map.Entry<String, Set<String>>>(
|
||||
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher,
|
||||
sortedGroupAssociations.entrySet(), zone + " Group Creation and Association",
|
||||
this.loggingInterval, this.workerThreads, 20);
|
||||
groupCreator.process(new Worker<Map.Entry<String, Set<String>>>()
|
||||
{
|
||||
|
||||
public String getIdentifier(Map.Entry<String, Set<String>> entry)
|
||||
{
|
||||
return entry.getKey() + " " + entry.getValue();
|
||||
}
|
||||
|
||||
public void process(Map.Entry<String, Set<String>> entry) throws Throwable
|
||||
{
|
||||
Set<String> parents = entry.getValue();
|
||||
String child = entry.getKey();
|
||||
|
||||
if (groupsToCreate.contains(child))
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger
|
||||
.debug("Removing '"
|
||||
String groupShortName = ChainingUserRegistrySynchronizer.this.authorityService
|
||||
.getShortName(child);
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger
|
||||
.debug("Creating group '" + groupShortName + "'");
|
||||
}
|
||||
// create the group
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.createAuthority(AuthorityType
|
||||
.getAuthorityType(child), groupShortName, groupShortName, zoneSet);
|
||||
}
|
||||
if (!parents.isEmpty())
|
||||
{
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
{
|
||||
for (String groupName : parents)
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.debug("Adding '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||
.getShortName(child)
|
||||
+ "' to group '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||
.getShortName(groupName) + "'");
|
||||
}
|
||||
}
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.addAuthority(parents, child);
|
||||
}
|
||||
Set<String> parentsToDelete = groupAssocsToDelete.get(child);
|
||||
if (parentsToDelete != null && !parentsToDelete.isEmpty())
|
||||
{
|
||||
for (String parent : parentsToDelete)
|
||||
{
|
||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.debug("Removing '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||
.getShortName(child)
|
||||
+ "' from group '"
|
||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||
.getShortName(parent) + "'");
|
||||
}
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.removeAuthority(parent, child);
|
||||
}
|
||||
}
|
||||
ChainingUserRegistrySynchronizer.this.authorityService.removeAuthority(parent, child);
|
||||
}
|
||||
}
|
||||
}, splitTxns);
|
||||
}
|
||||
}, splitTxns);
|
||||
}
|
||||
|
||||
// Process persons and their parent associations
|
||||
|
||||
lastModifiedMillis = getMostRecentUpdateTime(ChainingUserRegistrySynchronizer.PERSON_LAST_MODIFIED_ATTRIBUTE,
|
||||
zoneId);
|
||||
zoneId, splitTxns);
|
||||
lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
||||
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
||||
{
|
||||
@@ -778,8 +838,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
}
|
||||
}
|
||||
final BatchProcessor<NodeDescription> personProcessor = new BatchProcessor<NodeDescription>(
|
||||
this.retryingTransactionHelper, this.applicationEventPublisher, userRegistry.getPersons(lastModified),
|
||||
zone + " User Creation and Association", this.loggingInterval, this.workerThreads, 10);
|
||||
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher, userRegistry
|
||||
.getPersons(lastModified), zone + " User Creation and Association", this.loggingInterval,
|
||||
this.workerThreads, 10);
|
||||
class PersonWorker implements Worker<NodeDescription>
|
||||
{
|
||||
private long latestTime;
|
||||
@@ -822,7 +883,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
ChainingUserRegistrySynchronizer.logger.debug("Updating user '" + personName + "'");
|
||||
}
|
||||
ChainingUserRegistrySynchronizer.this.personService.setPersonProperties(personName,
|
||||
personProperties);
|
||||
personProperties, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -936,8 +997,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
if (force)
|
||||
{
|
||||
BatchProcessor<String> authorityDeletionProcessor = new BatchProcessor<String>(
|
||||
this.retryingTransactionHelper, this.applicationEventPublisher, deletionCandidates, zone
|
||||
+ " Authority Deletion", this.loggingInterval, this.workerThreads, 10);
|
||||
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher,
|
||||
deletionCandidates, zone + " Authority Deletion", this.loggingInterval, this.workerThreads, 10);
|
||||
class AuthorityDeleter implements Worker<String>
|
||||
{
|
||||
private int personProcessedCount;
|
||||
@@ -1062,11 +1123,18 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
* the zone id
|
||||
* @return the most recent update time in milliseconds
|
||||
*/
|
||||
private long getMostRecentUpdateTime(String label, String zoneId)
|
||||
private long getMostRecentUpdateTime(final String label, final String zoneId, boolean splitTxns)
|
||||
{
|
||||
Attribute attribute = this.attributeService.getAttribute(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH
|
||||
+ '/' + label + '/' + zoneId);
|
||||
return attribute == null ? -1 : attribute.getLongValue();
|
||||
return this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Long>()
|
||||
{
|
||||
|
||||
public Long execute() throws Throwable
|
||||
{
|
||||
Attribute attribute = ChainingUserRegistrySynchronizer.this.attributeService
|
||||
.getAttribute(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH + '/' + label + '/' + zoneId);
|
||||
return attribute == null ? -1 : attribute.getLongValue();
|
||||
}
|
||||
}, true, splitTxns);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1144,24 +1212,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
||||
{
|
||||
public Object doWork() throws Exception
|
||||
{
|
||||
return ChainingUserRegistrySynchronizer.this.retryingTransactionHelper
|
||||
.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronize(false, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.warn(
|
||||
"Failed initial synchronize with user registries", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
synchronize(false, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ChainingUserRegistrySynchronizer.logger.warn("Failed initial synchronize with user registries",
|
||||
e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
}
|
||||
|
@@ -171,15 +171,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
{
|
||||
newGroup("G2", "U1", "U3", "U4"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U5")
|
||||
}));
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.synchronizer.synchronize(true, true);
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
@@ -200,7 +192,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
assertExists("Z2", "G7", "U5");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,22 +201,14 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
* @throws Exception
|
||||
* the exception
|
||||
*/
|
||||
private void tearDownTestUsersAndGroups() throws Exception
|
||||
public void tearDownTestUsersAndGroups() throws Exception
|
||||
{
|
||||
// Wipe out everything that was in Z1 and Z2
|
||||
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", new NodeDescription[] {},
|
||||
new NodeDescription[] {}), new MockUserRegistry("Z1", new NodeDescription[] {},
|
||||
new NodeDescription[] {}), new MockUserRegistry("Z2", new NodeDescription[] {},
|
||||
new NodeDescription[] {}));
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.synchronizer.synchronize(true, true);
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
@@ -245,7 +229,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
assertNotExists("G7");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,15 +332,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
{
|
||||
newGroup("G2", "U1", "U3", "U4", "U6"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U4", "U5")
|
||||
}));
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.synchronizer.synchronize(true, true);
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
@@ -378,7 +354,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
assertExists("Z2", "G7");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, false, true);
|
||||
tearDownTestUsersAndGroups();
|
||||
}
|
||||
|
||||
@@ -393,15 +369,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
List<NodeDescription> persons = new ArrayList<NodeDescription>(new RandomPersonCollection(100));
|
||||
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(100, persons));
|
||||
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", persons, groups));
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
this.synchronizer.synchronize(true, true);
|
||||
tearDownTestUsersAndGroups();
|
||||
}
|
||||
|
||||
@@ -413,20 +381,20 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
*/
|
||||
public void dontTestAssocs() throws Exception
|
||||
{
|
||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||
{
|
||||
public Object execute() throws Throwable
|
||||
{
|
||||
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
||||
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
||||
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
||||
ChainingUserRegistrySynchronizerTest.this.applicationContextManager
|
||||
.setUserRegistries(new MockUserRegistry("Z0", Collections.<NodeDescription> emptyList(), groups));
|
||||
;
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
List<NodeDescription> groups = this.retryingTransactionHelper.doInTransaction(
|
||||
new RetryingTransactionCallback<List<NodeDescription>>()
|
||||
{
|
||||
|
||||
public List<NodeDescription> execute() throws Throwable
|
||||
{
|
||||
return new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
||||
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
||||
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
||||
}
|
||||
}, true, true);
|
||||
ChainingUserRegistrySynchronizerTest.this.applicationContextManager.setUserRegistries(new MockUserRegistry(
|
||||
"Z0", Collections.<NodeDescription> emptyList(), groups));
|
||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||
tearDownTestUsersAndGroups();
|
||||
}
|
||||
|
||||
@@ -631,10 +599,9 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
{
|
||||
return this.zoneId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.security.sync.UserRegistry#processDeletions(java.util.Set)
|
||||
*/
|
||||
public void processDeletions(Set<String> candidateAuthoritiesForDeletion)
|
||||
@@ -649,7 +616,8 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.security.sync.UserRegistry#getGroups(java.util.Date)
|
||||
*/
|
||||
public Collection<NodeDescription> getGroups(Date modifiedSince)
|
||||
|
Reference in New Issue
Block a user