/*
* Copyright (c) 2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.humantask.core.configuration;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlbeans.XmlException;
import org.quartz.CronExpression;
import org.wso2.carbon.humantask.core.HumanTaskConstants;
import org.wso2.carbon.humantask.core.dao.TaskStatus;
import org.wso2.carbon.humantask.server.config.*;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The memory model of the humantask configuration - humantask.xml.
*/
public class HumanTaskServerConfiguration {
private static final Log log = LogFactory.getLog(HumanTaskServerConfiguration.class);
private HumanTaskServerConfigDocument htServerConfigDocument;
private String dataSourceName;
private String dataSourceJNDIRepoInitialContextFactory;
private String dataSourceJNDIRepoProviderURL;
private boolean generateDdl = false;
private boolean showSql = false;
private String daoConnectionFactoryClass;
private String peopleQueryEvaluatorClass =
"org.wso2.carbon.humantask.core.integration.CarbonUserManagerBasedPeopleQueryEvaluator";
private int threadPoolMaxSize = 50;
// private String transactionFactoryClass = "com.atomikos.icatch.jta.UserTransactionManager";
private String transactionFactoryClass = "org.apache.ode.il.EmbeddedGeronimoFactory";
private List<TaskStatus> removableTaskStatuses = Collections.emptyList();
private List<String> eventListenerClassNames = new ArrayList<String>();
private String taskCleanupCronExpression;
private boolean uiRenderingEnabled = false;
private boolean emailNotificationEnabled = false;
private boolean smsNotificationEnabled = false;
// HT-Coordination Related Properties
private boolean htCoordinationEnabled = false;
private boolean taskRegistrationEnabled = false;
private String registrationServiceAuthUsername;
private String registrationServiceAuthPassword;
private boolean clusteredTaskEngines = false;
private String loadBalancerURL;
private boolean cachingEnabled = false;
private int cacheExpiryDuration = HumanTaskConstants.DEFAULT_CACHE_EXPIRY_DURATION;
private File htServerConfigurationFile;
private boolean isTaskOperationsForBusinessAdministratorEnabled = false;
private boolean validateTaskBeforeDeployment = false;
/**
* Create Human Task Server Configuration from a configuration file. If error occurred while parsing configuration
* file, default configuration will be created.
*
* @param htServerConfig XMLBeans object of human task server configuration file
*/
public HumanTaskServerConfiguration(File htServerConfig) {
htServerConfigDocument = readConfigurationFromFile(htServerConfig);
if (htServerConfigDocument == null) {
return;
}
// This is for HT-Coordination configuration.
this.htServerConfigurationFile = htServerConfig;
initConfigurationFromFile();
}
public HumanTaskServerConfiguration() {
this.dataSourceName = "bpsds";
this.daoConnectionFactoryClass = "org.wso2.carbon.humantask.dao.jpa.openjpa.HumanTaskDAOConnectionFactoryImpl";
this.dataSourceJNDIRepoInitialContextFactory = "com.sun.jndi.rmi.registry.RegistryContextFactory";
this.dataSourceJNDIRepoProviderURL = "rmi://localhost:2199";
this.peopleQueryEvaluatorClass = "org.wso2.carbon.humantask.core.integration.CarbonUserManagerBasedPeopleQueryEvaluator";
// this.threadPoolMaxSize = 50;
this.htCoordinationEnabled = false;
this.taskRegistrationEnabled = false;
this.clusteredTaskEngines = false;
}
private HumanTaskServerConfigDocument readConfigurationFromFile(File htServerConfiguration) {
try {
return HumanTaskServerConfigDocument.Factory.parse(new FileInputStream(htServerConfiguration));
} catch (XmlException e) {
log.error("Error parsing human task server configuration.", e);
} catch (FileNotFoundException e) {
log.info("Cannot find the human task server configuration in specified location "
+ htServerConfiguration.getPath() + " . Loads the default configuration.");
} catch (IOException e) {
log.error("Error reading human task server configuration file" + htServerConfiguration.getPath() + " .");
}
return null;
}
// Initialise the configuration object from the properties in the human task server config xml file.
private void initConfigurationFromFile() {
THumanTaskServerConfig tHumanTaskServerConfig = htServerConfigDocument.getHumanTaskServerConfig();
if (tHumanTaskServerConfig == null) {
return;
}
if (tHumanTaskServerConfig.getPersistenceConfig() != null) {
initPersistenceConfig(tHumanTaskServerConfig.getPersistenceConfig());
}
if (tHumanTaskServerConfig.getPeopleQueryEvaluatorConfig() != null) {
initPeopleQueryEvaluator(tHumanTaskServerConfig.getPeopleQueryEvaluatorConfig());
}
if(tHumanTaskServerConfig.getEnableTaskOperationsForBusinessAdministrator())
{
this.isTaskOperationsForBusinessAdministratorEnabled = true;
}
if (tHumanTaskServerConfig.getSchedulerConfig() != null) {
initSchedulerConfig(tHumanTaskServerConfig.getSchedulerConfig());
}
if (tHumanTaskServerConfig.getTransactionManagerConfig() != null) {
initTransactionManagerConfig(tHumanTaskServerConfig.getTransactionManagerConfig());
}
if (tHumanTaskServerConfig.getTaskCleanupConfig() != null) {
iniTaskCleanupConfig(tHumanTaskServerConfig.getTaskCleanupConfig());
}
if(tHumanTaskServerConfig.getTaskEventListeners() != null) {
initEventListeners(tHumanTaskServerConfig.getTaskEventListeners());
}
if(tHumanTaskServerConfig.getUIRenderingEnabled()) {
uiRenderingEnabled = true;
}
if (tHumanTaskServerConfig.getHumanTaskCoordination() != null) {
initCoordinationConfiguration(tHumanTaskServerConfig.getHumanTaskCoordination());
}
if (tHumanTaskServerConfig.getCacheConfiguration() != null) {
initCacheConfiguration(tHumanTaskServerConfig.getCacheConfiguration());
}
if(tHumanTaskServerConfig.getEnableTaskValidationBeforeDeployment()) {
validateTaskBeforeDeployment = true;
}
if(tHumanTaskServerConfig.getEnableEMailNotification()) {
emailNotificationEnabled = true;
}
if(tHumanTaskServerConfig.getEnableSMSNotification()) {
smsNotificationEnabled = true;
}
}
private void iniTaskCleanupConfig(TTaskCleanupConfig taskCleanupConfig) {
if (taskCleanupConfig != null) {
if (StringUtils.isNotEmpty(taskCleanupConfig.getCronExpression())) {
if (CronExpression.isValidExpression(taskCleanupConfig.getCronExpression().trim())) {
this.taskCleanupCronExpression = taskCleanupConfig.getCronExpression();
} else {
String warnMsg = String.format("The task clean up cron expression[%s] is invalid." +
" Ignoring task clean up configurations! ",
taskCleanupConfig.getCronExpression());
log.warn(warnMsg);
return;
}
}
if (StringUtils.isNotEmpty(taskCleanupConfig.getStatuses())) {
String[] removableStatusesArray = taskCleanupConfig.getStatuses().split(",");
List<TaskStatus> removableTaskStatusList = new ArrayList<TaskStatus>();
for (String removableStatus : removableStatusesArray) {
for (TaskStatus taskStatusEnum : TaskStatus.values()) {
if (taskStatusEnum.toString().equals(removableStatus.trim())) {
removableTaskStatusList.add(taskStatusEnum);
break;
}
}
}
this.removableTaskStatuses = removableTaskStatusList;
}
}
}
private void initEventListeners(TTaskEventListeners taskEventListeners) {
if(taskEventListeners.getClassNameArray() != null) {
for(String eventListenerClassName : taskEventListeners.getClassNameArray()) {
if(StringUtils.isNotEmpty(eventListenerClassName)) {
this.eventListenerClassNames.add(eventListenerClassName.trim());
}
}
}
}
private void initTransactionManagerConfig(TTransactionManagerConfig tTransactionManagerConfig) {
if (tTransactionManagerConfig.getTransactionManagerClass() != null) {
this.transactionFactoryClass = tTransactionManagerConfig.getTransactionManagerClass().
trim();
} else {
log.debug("TransactionManagerClass not provided with HumanTask configuration." +
"Using default TransactionManagerClass :" + transactionFactoryClass);
}
}
private void initSchedulerConfig(TSchedulerConfig tSchedulerConfig) {
if (tSchedulerConfig.getMaxThreadPoolSize() > 0) {
this.threadPoolMaxSize = tSchedulerConfig.getMaxThreadPoolSize();
} else {
log.debug("ThreadPoolMaxSize not provided with HumanTask configuration." +
"Using default thread pool max value of :" + threadPoolMaxSize);
}
}
private void initPeopleQueryEvaluator(TPeopleQueryEvaluatorConfig tUserManagerConfig) {
if (tUserManagerConfig.getPeopleQueryEvaluatorClass() != null) {
this.peopleQueryEvaluatorClass = tUserManagerConfig.getPeopleQueryEvaluatorClass().trim();
} else {
log.debug("PeopleQueryEvaluatorConfig is not provided with HumanTask configuration." +
"Using default PeopleQueryEvaluatorClass: " + peopleQueryEvaluatorClass);
}
}
private void initPersistenceConfig(TPersistenceConfig tPersistenceConfig) {
if (tPersistenceConfig.getDataSource() != null) {
this.dataSourceName = tPersistenceConfig.getDataSource().trim();
}
if (tPersistenceConfig.getJNDIInitialContextFactory() != null) {
this.dataSourceJNDIRepoInitialContextFactory =
tPersistenceConfig.getJNDIInitialContextFactory().trim();
}
if (tPersistenceConfig.getJNDIProviderUrl() != null) {
this.dataSourceJNDIRepoProviderURL = tPersistenceConfig.getJNDIProviderUrl().trim();
int portOffset = getCarbonPortOffset();
// We need to adjust the port value according to the offset defined in the carbon configuration.
String portValueString = dataSourceJNDIRepoProviderURL.substring(
dataSourceJNDIRepoProviderURL.lastIndexOf(':') + 1,
dataSourceJNDIRepoProviderURL.length());
String urlWithoutPort = dataSourceJNDIRepoProviderURL
.substring(0, dataSourceJNDIRepoProviderURL.lastIndexOf(':') + 1);
int actualPortValue = Integer.parseInt(portValueString);
int correctedPortValue = actualPortValue + portOffset;
this.dataSourceJNDIRepoProviderURL = urlWithoutPort.concat(Integer.toString(correctedPortValue));
}
if (tPersistenceConfig.getDAOConnectionFactoryClass() != null) {
this.daoConnectionFactoryClass = tPersistenceConfig.getDAOConnectionFactoryClass().trim();
}
this.generateDdl = tPersistenceConfig.getGenerateDdl();
this.showSql = tPersistenceConfig.getShowSql();
}
private void initCoordinationConfiguration(THumanTaskCoordination humanTaskCoordination) {
this.htCoordinationEnabled = humanTaskCoordination.getTaskCoordinationEnabled();
this.taskRegistrationEnabled = humanTaskCoordination.getTaskRegistrationEnabled();
if (humanTaskCoordination.getRegistrationServiceAuthentication() != null) {
getAuthenticationConfig(htServerConfigurationFile, humanTaskCoordination.getRegistrationServiceAuthentication());
}
if (humanTaskCoordination.getClusteredTaskEngines() != null) {
this.clusteredTaskEngines = true;
parseClusterDetails(humanTaskCoordination.getClusteredTaskEngines());
}
}
private void parseClusterDetails(TClusterConfig clusterConfig) {
if (clusterConfig.getLoadBalancerURL() != null) {
this.loadBalancerURL = clusterConfig.getLoadBalancerURL();
} else {
this.clusteredTaskEngines = false;
}
}
private void getAuthenticationConfig(File file, TRegServiceAuth authentication) {
//Since secretResolver only accept Element we have to build Element here.
SecretResolver secretResolver = null;
InputStream in = null;
try {
in = new FileInputStream(file);
StAXOMBuilder builder = new StAXOMBuilder(in);
secretResolver = SecretResolverFactory.create(builder.getDocumentElement(), true);
} catch (Exception e) {
log.warn("Error occurred while retrieving secured TaskEngineProtocolHandler configuration.", e);
} finally {
try {
if(in != null) {
in.close();
}
} catch (IOException e) {
log.error(e.getLocalizedMessage(), e);
}
}
// Get Username
if (secretResolver != null && secretResolver.isInitialized()
&& secretResolver.isTokenProtected(HumanTaskConstants.B4P_REGISTRATIONS_USERNAME_ALIAS)) {
this.registrationServiceAuthUsername = secretResolver.resolve(HumanTaskConstants.B4P_REGISTRATIONS_USERNAME_ALIAS);
if (log.isDebugEnabled()) {
log.debug("Loaded Registration service admin username from secure vault");
}
} else {
if (authentication.getUsername() != null) {
this.registrationServiceAuthUsername = authentication.getUsername();
}
}
// Get Password
if (secretResolver != null && secretResolver.isInitialized()
&& secretResolver.isTokenProtected(HumanTaskConstants.B4P_REGISTRATIONS_PASSWORD_ALIAS)) {
this.registrationServiceAuthPassword = secretResolver.resolve(HumanTaskConstants.B4P_REGISTRATIONS_PASSWORD_ALIAS);
if (log.isDebugEnabled()) {
log.debug("Loaded Registration service admin password from secure vault");
}
} else {
if (authentication.getPassword() != null) {
this.registrationServiceAuthPassword = authentication.getPassword();
}
}
}
private void initCacheConfiguration(TCacheConfiguration cacheConfiguration) {
this.cachingEnabled = cacheConfiguration.getEnableCaching();
if (cachingEnabled) {
if (cacheConfiguration.getCacheExpiryDuration() >= 0) {
this.cacheExpiryDuration = cacheConfiguration.getCacheExpiryDuration();
} else {
log.warn("The Cache Expiry duration is invalid. Using default Cache expiry duration :"
+ HumanTaskConstants.DEFAULT_CACHE_EXPIRY_DURATION + " seconds");
}
}
}
//gets the carbon port offset value.
private int getCarbonPortOffset() {
String offset = CarbonUtils.getServerConfiguration().getFirstProperty(
HumanTaskConstants.CARBON_CONFIG_PORT_OFFSET_NODE);
try {
return ((offset != null) ? Integer.parseInt(offset.trim()) :
0);
} catch (NumberFormatException e) {
log.warn("Error occurred while reading port offset. Invalid port offset: " +
offset + " Setting the port offset to 0",
e);
return 0;
}
}
/**
* @return : The data source name.
*/
public String getDataSourceName() {
return dataSourceName;
}
/**
* @return :
*/
public String getDataSourceJNDIRepoInitialContextFactory() {
return dataSourceJNDIRepoInitialContextFactory;
}
/**
* @return : the JNDI repo provider URL.
*/
public String getDataSourceJNDIRepoProviderURL() {
return dataSourceJNDIRepoProviderURL;
}
/**
* @return : Return the is generate DDL option in the server configuration.
*/
public boolean isGenerateDdl() {
return generateDdl;
}
/**
* @return : The value of the show sqp property in the config file.
*/
public boolean isShowSql() {
return showSql;
}
/**
* @return : the dao connection factory class.
*/
public String getDaoConnectionFactoryClass() {
return daoConnectionFactoryClass;
}
/**
* @return : The class name of the people query evaluation implementation.
*/
public String getPeopleQueryEvaluatorClass() {
return peopleQueryEvaluatorClass;
}
/**
* @return : The thread pool max size.
*/
public int getThreadPoolMaxSize() {
return threadPoolMaxSize;
}
/**
* @return : The transaction factory class.
*/
public String getTransactionFactoryClass() {
return transactionFactoryClass;
}
/**
* @return : The task cleanup cron expression.
*/
public String getTaskCleanupCronExpression() {
return taskCleanupCronExpression;
}
/**
* @return : The list of event listener classes in the humantask config file.
*/
public List<String> getEventListenerClassNames() {
return this.eventListenerClassNames;
}
/**
* @return : Return the list of removable task statuses in the humantask config file.
*/
public List<TaskStatus> getRemovableTaskStatuses() {
return removableTaskStatuses;
}
/**
* @return : true if we have a valid task cleanup configuration parameters. False otherwise.
*/
public boolean isTaskCleanupEnabled() {
return StringUtils.isNotEmpty(this.taskCleanupCronExpression) &&
CronExpression.isValidExpression(taskCleanupCronExpression) &&
removableTaskStatuses.size() > 0;
}
public boolean isUiRenderingEnabled() {
return uiRenderingEnabled;
}
/**
* @return true if HumanTask coordination enabled.
*/
public boolean isHtCoordinationEnabled() {
return htCoordinationEnabled;
}
public boolean isTaskRegistrationEnabled() {
return taskRegistrationEnabled;
}
/**
*
* @return Username of the B4P coordination component's registration service
*/
public String getRegistrationServiceAuthUsername() {
return registrationServiceAuthUsername;
}
/**
* @return User Password of the B4P coordination component's registration service.
*/
public String getRegistrationServiceAuthPassword() {
return registrationServiceAuthPassword;
}
public String getLoadBalancerURL() {
return loadBalancerURL;
}
public boolean isClusteredTaskEngines() {
return clusteredTaskEngines;
}
public boolean isCachingEnabled() {
return cachingEnabled;
}
public int getCacheExpiryDuration() {
return cacheExpiryDuration;
}
public boolean isTaskOperationsForBusinessAdministratorEnabled() {
return isTaskOperationsForBusinessAdministratorEnabled;
}
public boolean getEnableTaskValidationBeforeDeployment(){
return validateTaskBeforeDeployment;
}
public boolean getEnableEMailNotification() {
return emailNotificationEnabled;
}
public boolean getEnableSMSNotification() {
return smsNotificationEnabled;
}
}