use of org.alfresco.util.TraceableThreadFactory in project alfresco-repository by Alfresco.
the class ChainingUserRegistrySynchronizer method synchronizeInternal.
private void synchronizeInternal(boolean forceUpdate, boolean isFullSync, final boolean splitTxns) {
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
if (forceUpdate) {
ChainingUserRegistrySynchronizer.logger.debug("Running a full sync.");
} else {
ChainingUserRegistrySynchronizer.logger.debug("Running a differential sync.");
}
if (allowDeletions) {
ChainingUserRegistrySynchronizer.logger.debug("deletions are allowed");
} else {
ChainingUserRegistrySynchronizer.logger.debug("deletions are not allowed");
}
// Don't proceed with the sync if the repository is read only
if (this.transactionService.isReadOnly()) {
ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
return;
}
}
// Don't proceed with the sync if the repository is read only
if (this.transactionService.isReadOnly()) {
ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
return;
}
// Create a background executor that will refresh our lock. This means we can request a lock with a relatively
// small persistence time and not worry about it lasting after server restarts. Note we use an independent
// executor because this is a compound operation that spans accross multiple batch processors.
String lockToken = null;
TraceableThreadFactory threadFactory = new TraceableThreadFactory();
threadFactory.setNamePrefix("ChainingUserRegistrySynchronizer lock refresh");
threadFactory.setThreadDaemon(true);
ScheduledExecutorService lockRefresher = new ScheduledThreadPoolExecutor(1, threadFactory);
// Let's ensure all exceptions get logged
try {
// First, try to obtain a lock to ensure we are the only node trying to run this job
try {
if (splitTxns) {
// 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.
lockToken = this.transactionService.getRetryingTransactionHelper().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 {
// If this is a login-triggered sync, give it a few retries before giving up
lockToken = this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL, 3000, 10);
}
} catch (LockAcquisitionException e) {
// Don't proceed with the sync if it is running on another node
ChainingUserRegistrySynchronizer.logger.warn("User registry synchronization already running in another thread. Synchronize aborted");
return;
}
// Schedule the lock refresh to run at regular intervals
final String token = lockToken;
lockRefresher.scheduleAtFixedRate(new Runnable() {
public void run() {
ChainingUserRegistrySynchronizer.this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {
public Object execute() throws Throwable {
ChainingUserRegistrySynchronizer.this.jobLockService.refreshLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL);
return null;
}
}, false, splitTxns);
}
}, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, TimeUnit.MILLISECONDS);
Set<String> visitedZoneIds = new TreeSet<String>();
Collection<String> instanceIds = this.applicationContextManager.getInstanceIds();
// Work out the set of all zone IDs in the authentication chain so that we can decide which users / groups
// need 're-zoning'
Set<String> allZoneIds = new TreeSet<String>();
for (String id : instanceIds) {
allZoneIds.add(AuthorityService.ZONE_AUTH_EXT_PREFIX + id);
}
// Collect the plugins that we can sync : zoneId, plugin
Map<String, UserRegistry> plugins = new HashMap<String, UserRegistry>();
for (String id : instanceIds) {
UserRegistry plugin;
try {
ApplicationContext context = this.applicationContextManager.getApplicationContext(id);
plugin = (UserRegistry) context.getBean(this.sourceBeanName);
} catch (RuntimeException e) {
// The bean doesn't exist or this subsystem won't start. The reason would have been logged. Ignore and continue.
continue;
}
if (!(plugin instanceof ActivateableBean) || ((ActivateableBean) plugin).isActive()) {
// yes this plugin needs to be synced
plugins.put(id, plugin);
}
}
/**
* Sync starts here
*/
notifySyncStart(plugins.keySet());
for (String id : instanceIds) {
UserRegistry plugin = plugins.get(id);
if (plugin != null) {
// If debug is enabled then dump out the contents of the authentication JMX bean
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
mbeanServer = (MBeanServerConnection) getApplicationContext().getBean("alfrescoMBeanServer");
try {
StringBuilder nameBuff = new StringBuilder(200).append("Alfresco:Type=Configuration,Category=Authentication,id1=managed,id2=").append(URLDecoder.decode(id, "UTF-8"));
ObjectName name = new ObjectName(nameBuff.toString());
if (mbeanServer != null && mbeanServer.isRegistered(name)) {
MBeanInfo info = mbeanServer.getMBeanInfo(name);
MBeanAttributeInfo[] attributes = info.getAttributes();
ChainingUserRegistrySynchronizer.logger.debug(id + " attributes:");
for (MBeanAttributeInfo attribute : attributes) {
Object value = mbeanServer.getAttribute(name, attribute.getName());
ChainingUserRegistrySynchronizer.logger.debug(attribute.getName() + " = " + value);
}
}
} catch (UnsupportedEncodingException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (MalformedObjectNameException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (InstanceNotFoundException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (IntrospectionException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (AttributeNotFoundException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (ReflectionException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (MBeanException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
} catch (IOException e) {
if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
}
}
}
// end of debug dump of active JMX bean
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled()) {
ChainingUserRegistrySynchronizer.logger.info("Synchronizing users and groups with user registry '" + id + "'");
}
if (isFullSync && ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
if (allowDeletions) {
ChainingUserRegistrySynchronizer.logger.warn("Some users and groups previously created by synchronization with this user registry may be removed.");
} else {
ChainingUserRegistrySynchronizer.logger.warn("Deletions are disabled. Users and groups removed from this registry will be logged only and will remain in the repository. Users previously found in a different registry will be moved in the repository rather than recreated.");
}
}
// Work out whether we should do the work in a separate transaction (it's most performant if we
// bunch it into small transactions, but if we are doing a sync on login, it has to be the same
// transaction)
boolean requiresNew = splitTxns || AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
try {
/**
* Do the sync with the specified plugin
*/
syncWithPlugin(id, plugin, forceUpdate, isFullSync, requiresNew, visitedZoneIds, allZoneIds);
this.applicationEventPublisher.publishEvent(new SynchronizeDirectoryEndEvent(this, id));
} catch (final RuntimeException e) {
notifySyncDirectoryEnd(id, e);
throw e;
}
}
// if plugin exists
}
// for each instanceId
// End of successful synchronization here
notifySyncEnd();
} catch (final RuntimeException e) {
notifySyncEnd(e);
ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
throw e;
} finally {
// Release the lock if necessary
if (lockToken != null) {
// Cancel the lock refresher
// Because we may hit a perfect storm when trying to interrupt workers in their unsynchronized getTask()
// method we can't wait indefinitely and may have to retry the shutdown
int trys = 0;
do {
lockRefresher.shutdown();
try {
lockRefresher.awaitTermination(ChainingUserRegistrySynchronizer.LOCK_TTL, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
} while (!lockRefresher.isTerminated() && trys++ < 3);
if (!lockRefresher.isTerminated()) {
lockRefresher.shutdownNow();
ChainingUserRegistrySynchronizer.logger.error("Failed to shut down lock refresher");
}
final String token = lockToken;
this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {
public Object execute() throws Throwable {
ChainingUserRegistrySynchronizer.this.jobLockService.releaseLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME);
return null;
}
}, false, splitTxns);
}
}
}
use of org.alfresco.util.TraceableThreadFactory in project SearchServices by Alfresco.
the class DefaultTrackerPoolFactory method create.
@Override
public ThreadPoolExecutor create() {
// We need a thread factory
TraceableThreadFactory threadFactory = new TraceableThreadFactory();
threadFactory.setThreadDaemon(threadDaemon);
threadFactory.setThreadPriority(threadPriority);
if (poolName.length() > 0) {
threadFactory.setNamePrefix(poolName);
}
BlockingQueue<Runnable> workQueue;
if (workQueueSize < 0) {
// We can have an unlimited queue, as we have a sensible thread pool!
workQueue = new LinkedBlockingQueue<Runnable>();
} else {
// Use an array one for consistent performance on a small queue size
workQueue = new ArrayBlockingQueue<Runnable>(workQueueSize);
}
ThreadPoolExecutor threadPoolExecutor = new DynamicallySizedThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, rejectedExecutionHandler);
return threadPoolExecutor;
}
use of org.alfresco.util.TraceableThreadFactory in project alfresco-repository by Alfresco.
the class DictionaryLoadDAOTest method initDictionaryCaches.
private void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO, TenantService tenantService) throws Exception {
CompiledModelsCache compiledModelsCache = new CompiledModelsCache();
compiledModelsCache.setDictionaryDAO(dictionaryDAO);
compiledModelsCache.setTenantService(tenantService);
compiledModelsCache.setRegistry(new DefaultAsynchronouslyRefreshedCacheRegistry());
TraceableThreadFactory threadFactory = new TraceableThreadFactory();
threadFactory.setThreadDaemon(true);
threadFactory.setThreadPriority(Thread.NORM_PRIORITY);
ThreadPoolExecutor threadPoolExecutor = new DynamicallySizedThreadPoolExecutor(20, 20, 90, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
compiledModelsCache.setThreadPoolExecutor(threadPoolExecutor);
dictionaryDAO.setDictionaryRegistryCache(compiledModelsCache);
dictionaryDAO.init();
}
Aggregations