/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see .
*/
package org.alfresco.repo.config.xml;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.config.ConfigDataCache;
import org.alfresco.repo.config.ConfigDataCache.ConfigData;
import org.alfresco.repo.config.ConfigDataCache.ImmutableConfigData;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantDeployer;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.config.ConfigDeployment;
import org.springframework.extensions.config.ConfigImpl;
import org.springframework.extensions.config.ConfigSection;
import org.springframework.extensions.config.ConfigSource;
import org.springframework.extensions.config.evaluator.Evaluator;
import org.springframework.extensions.config.xml.XMLConfigService;
import org.springframework.extensions.config.xml.elementreader.ConfigElementReader;
/**
* XML-based configuration service which can optionally read config from the Repository
*/
public class RepoXMLConfigService extends XMLConfigService implements TenantDeployer
{
private static final Log logger = LogFactory.getLog(RepoXMLConfigService.class);
/**
* Configuration that is manipulated by the current thread.
* This is required because the super classes call back into this mechanism after
* receiving the initial object, etc.
*/
private final ThreadLocal configUnderConstruction = new ThreadLocal();
// Dependencies
private TransactionService transactionService;
private ConfigDataCache configDataCache;
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
/**
* Set the asynchronously-controlled cache.
*/
public void setConfigDataCache(ConfigDataCache configDataCache)
{
this.configDataCache = configDataCache;
}
/**
* Constructs an XMLConfigService using the given config source
*/
public RepoXMLConfigService(ConfigSource configSource)
{
super(configSource);
}
@Override
public List initConfig()
{
configDataCache.refresh();
// Just return whatever is there (no-one uses it)
ConfigData configData = configDataCache.get();
return configData.getConfigDeployments();
}
/**
* Get the repository configuration data for a given tenant.
* This does the low-level initialization of the configuration and does not do any
* caching.
*
* @param tenantDomain the current tenant domain
* @return return the repository configuration for the given tenant (never null)
*/
public ConfigData getRepoConfig(final String tenantDomain)
{
final RetryingTransactionCallback getConfigWork = new RetryingTransactionCallback()
{
@Override
public Void execute() throws Throwable
{
// parse config
RepoXMLConfigService.super.initConfig();
return null;
}
};
TenantUtil.TenantRunAsWork getConfigRunAs = new TenantUtil.TenantRunAsWork()
{
@Override
public Void doWork() throws Exception
{
transactionService.getRetryingTransactionHelper().doInTransaction(getConfigWork, true);
return null;
}
};
try
{
if (logger.isDebugEnabled())
{
logger.debug(
"Fetching repository config data for tenant: \n" +
" Tenant Domain: " + tenantDomain);
}
// Put some mutable config onto the current thread and have the superclasses mess with that.
ConfigData configData = new ConfigData();
configUnderConstruction.set(configData);
// Do the work as system tenant, see ALF-19922
TenantUtil.runAsSystemTenant(getConfigRunAs, tenantDomain);
// Now wrap the config so that it cannot be changed
configData = new ImmutableConfigData(configData);
// Done
if (logger.isDebugEnabled())
{
logger.debug(
"Fetched repository config data for tenant: \n" +
" Tenant Domain: " + tenantDomain + "\n" +
" Config: " + configData);
}
return configData;
}
catch (Exception e)
{
throw new AlfrescoRuntimeException(
"Failed to fetch repository config data for tenant \n" +
" Tenant Domain: " + tenantDomain,
e);
}
finally
{
configUnderConstruction.remove();
}
}
@Override
public void destroy()
{
reset();
}
/**
* Resets the config values for the current tenant
*/
@Override
public void reset()
{
configDataCache.refresh();
}
@Override
protected void onBootstrap(ApplicationEvent event)
{
// run as System on bootstrap
AuthenticationUtil.runAs(new RunAsWork