/* * Copyright (c) 2015, 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.mediation.ntask; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Callable; import org.apache.axis2.description.Parameter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.SynapseConstants; import org.apache.synapse.commons.util.MiscellaneousUtil; import org.apache.synapse.task.SynapseTaskException; import org.apache.synapse.task.TaskDescription; import org.apache.synapse.task.TaskManager; import org.apache.synapse.task.TaskManagerObserver; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.core.ServerStartupHandler; import org.wso2.carbon.mediation.ntask.internal.NtaskService; import org.wso2.carbon.ntask.common.TaskException; import org.wso2.carbon.ntask.core.TaskInfo; import org.wso2.carbon.ntask.core.impl.clustered.ClusteredTaskManager; import org.wso2.carbon.ntask.core.service.TaskService; import org.wso2.carbon.utils.CarbonUtils; import com.hazelcast.core.IExecutorService; public class NTaskTaskManager implements TaskManager, TaskServiceObserver, ServerStartupHandler { private final Object lock = new Object(); private static final Log logger = LogFactory.getLog(NTaskTaskManager.class.getName()); /** * TODO ClusterGroupCommunicator NTASK_P2P_COMM_EXECUTOR is private in the carbon-commons-4.4.1 release, * this should be changed to use ClusterGroupCommunicator.NTASK_P2P_COMM_EXECUTOR. */ private static final String NTASK_P2P_COMM_EXECUTOR = "__NTASK_P2P_COMM_EXECUTOR__"; private String name; private boolean initialized = false; private org.wso2.carbon.ntask.core.TaskManager taskManager; private final Map<String, Object> properties = new HashMap<String, Object>(5); protected final Properties configProperties = new Properties(); private final List<TaskManagerObserver> observers = new ArrayList<TaskManagerObserver>(); private final List<TaskDescription> taskQueue = new ArrayList<TaskDescription>(); private final Object taskQueueLock = new Object(); @Override public boolean schedule(TaskDescription taskDescription) { logger.debug("#schedule Scheduling task : " + taskId(taskDescription)); TaskInfo taskInfo; try { taskInfo = TaskBuilder.buildTaskInfo(taskDescription, properties); } catch (Exception e) { if (logger.isDebugEnabled()) { logger.debug("#schedule Could not build task info object of task : " +taskId(taskDescription)+ ". Error: " + e.getLocalizedMessage(), e); } synchronized (lock) { queueTask(taskDescription); } return false; } if (!isInitialized()) { // if cannot schedule yet, put in the pending tasks list. synchronized (lock) { logger.debug("#schedule Added pending task : " + taskId(taskDescription)); queueTask(taskDescription); } return false; } try { synchronized (lock) { if (taskManager == null) { logger.debug("#schedule Could not schedule task " + taskId(taskDescription) + ". Task manager is not available."); queueTask(taskDescription); return false; } taskManager.registerTask(taskInfo); taskManager.scheduleTask(taskInfo.getName()); removeTask(taskDescription); } logger.info("Scheduled task " + taskId(taskDescription)); } catch (Exception e) { logger.error("Scheduling task [" + taskId(taskDescription) + "::" + taskDescription.getTaskGroup() + "] FAILED. Error: " + e.getLocalizedMessage(), e); return false; } return true; } @Override public boolean reschedule(String taskName, TaskDescription taskDescription) { if (!isInitialized()) { return false; } try { synchronized (lock) { if (taskManager == null) { logger.warn("#reschedule Could not reschedule task [" + taskName + "]. Task manager is not available."); return false; } TaskInfo taskInfo = taskManager.getTask(taskName); TaskDescription description = TaskBuilder.buildTaskDescription(taskInfo); taskInfo = TaskBuilder.buildTaskInfo(description, properties); taskManager.registerTask(taskInfo); taskManager.rescheduleTask(taskInfo.getName()); } } catch (Exception e) { return false; } return true; } @Override public boolean delete(String taskName) { if (!isInitialized()) { return false; } if (taskName == null) { return false; } String list[] = taskName.split("::"); String name = list[0]; if (name == null || "".equals(name)) { throw new SynapseTaskException("Task name is null. ", logger); } String group = null; if (list.length > 1) { group = list[1]; } if (group == null || "".equals(group)) { group = TaskDescription.DEFAULT_GROUP; if (logger.isDebugEnabled()) { logger.debug("#delete Task group is null or empty , using default group :" + TaskDescription.DEFAULT_GROUP); } } try { boolean deleted; synchronized (lock) { if (taskManager == null) { logger.warn("#delete Could not delete task [" + taskName + "]. Task manager is not available."); return false; } deleted = taskManager.deleteTask(name); NTaskAdapter.removeProperty(taskName); } logger.debug("Deleted task [" + name + "] [" + deleted + "]"); return deleted; } catch (Exception e) { logger.error("Cannot delete task [" + taskName + "::" + group + "]. Error: " + e.getLocalizedMessage(), e); return false; } } @Override public boolean pause(String taskName) { if (!isInitialized()) { return false; } try { synchronized (lock) { if (taskManager == null) { logger.warn("#pause Could not pause task [" + taskName + "]. Task manager is not available."); return false; } taskManager.pauseTask(taskName); } return true; } catch (Exception e) { logger.error("Cannot pause task [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } return false; } @Override public boolean pauseAll() { if (!isInitialized()) { return false; } try { synchronized (lock) { if (taskManager == null) { logger.warn("#pauseAll Could not pause any task. Task manager is not available."); return false; } List<TaskInfo> taskList = taskManager.getAllTasks(); for (TaskInfo taskInfo : taskList) { taskManager.pauseTask(taskInfo.getName()); } } return true; } catch (Exception e) { logger.error("Cannot pause all tasks. Error: " + e.getLocalizedMessage(), e); } return false; } @Override public boolean resume(String taskName) { if (!isInitialized()) { return false; } if (taskName == null) { return false; } try { synchronized (lock) { if (taskManager == null) { logger.warn("#resume Could not resume task [" + taskName + "]. Task manager is not available."); return false; } taskManager.resumeTask(taskName); } } catch (Exception e) { logger.error("Cannot resume task [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); return false; } return true; } @Override public boolean resumeAll() { if (!isInitialized()) { return false; } try { synchronized (lock) { if (taskManager == null) { logger.warn("#resumeAll Could not resume any task. Task manager is not available."); return false; } List<TaskInfo> taskList = taskManager.getAllTasks(); for (TaskInfo taskInfo : taskList) { taskManager.resumeTask(taskInfo.getName()); } } return true; } catch (Exception e) { logger.error("Cannot resume all tasks. Error: " + e.getLocalizedMessage(), e); } return false; } @Override public TaskDescription getTask(String taskName) { if (!isInitialized()) { return null; } try { TaskInfo taskInfo; synchronized (lock) { if (taskManager == null) { logger.warn("#getTask Could not retrieve task [" + taskName + "]. Task manager is not available."); return null; } taskInfo = taskManager.getTask(taskName); } return TaskBuilder.buildTaskDescription(taskInfo); } catch (Exception e) { logger.error("Cannot return task [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); return null; } } @Override public String[] getTaskNames() { if (!isInitialized()) { return new String[0]; } try { List<TaskInfo> taskList; synchronized (lock) { if (taskManager == null) { logger.warn("#getTaskNames Could not query task names. Task manager is not available."); return new String[0]; } taskList = taskManager.getAllTasks(); } List<String> result = new ArrayList<String>(); for (TaskInfo taskInfo : taskList) { result.add(taskInfo.getName()); } return result.toArray(new String[result.size()]); } catch (Exception e) { logger.error("Cannot return task list. Error: " + e.getLocalizedMessage(), e); } return new String[0]; } @Override public boolean init(Properties properties) { synchronized (lock) { try { TaskService taskService = NtaskService.getTaskService(); if (taskService == null || NtaskService.getCcServiceInstance() == null) { NtaskService.addObserver(this); return false; } if ((taskManager = getTaskManager(false)) == null) { logger.debug("#init Could not initialize task manager. " + managerId()); return false; } else { logger.debug("#init Obtained Carbon task manager " + managerId()); } initialized = true; if (isTaskRunningNode()) { taskService.registerTaskType(Constants.TASK_TYPE_ESB); updateAndCleanupObservers(); } logger.info("Initialized task manager. Tenant [" + getCurrentTenantId() + "]"); if (logger.isDebugEnabled()) { logger.debug("#init Initialized task manager : " + managerId()); logger.debug("#init Scheduling existing tasks if any. : " + managerId()); } Object[] taskDescriptions = pendingTasks(); for (Object d : taskDescriptions) { schedule((TaskDescription) d); } return true; } catch (Exception e) { logger.error("Cannot initialize task manager. Error: " + e.getLocalizedMessage(), e); initialized = false; } } return false; } /** * Helper method to decide whether this node is task running node or not. * * @return true if this node supposed to run tasks, false otherwise */ private boolean isTaskRunningNode() { boolean isStandaloneNode = NtaskService.getCcServiceInstance().getServerConfigContext() .getAxisConfiguration().getClusteringAgent() == null; boolean isWorkerNode = !isStandaloneNode && CarbonUtils.isWorkerNode(); if (logger.isDebugEnabled()) { logger.debug("#init standalone node: [" + isStandaloneNode + "] worker node: [" + isWorkerNode + "] " + managerId()); } if (isStandaloneNode || isWorkerNode) { return true; } /** * If this is not a worker node node in a cluster, then use "clusteringPattern" parameter in axis2.xml * clustering configs to decide whether to run tasks in this node or not, and that defaults to not * running tasks(defaulting to "WorkerManager" clustering pattern and this node is a manager node, hence * not running tasks in this node) */ Parameter parameter = NtaskService.getCcServiceInstance().getServerConfigContext() .getAxisConfiguration().getClusteringAgent().getParameter(Constants.CLUSTERING_PATTERN); if (parameter == null || parameter.getValue() == null || parameter.getValue().toString().isEmpty()) { logger.warn("clusteringPattern parameter not configured correctly in clustering configuration, " + "hence defaults to worker manager clustering pattern, and since this node is a manager node, " + "skips running tasks in this node" ); return false; } else if (parameter.getValue().toString().equals(Constants.CLUSTERING_PATTERN_WORKER_MANAGER)) { if (logger.isDebugEnabled()) { logger.debug("clustering pattern is worker manager clustering pattern, and this node is a " + "manager node, hence skip running tasks"); } return false; } else { if (logger.isDebugEnabled()) { logger.debug("Non worker manager clustering pattern mentioned, hence running tasks in this node"); } return true; } } @Override public boolean update(Map<String, Object> parameters) { return init(parameters == null || !parameters.containsKey("init.properties") ? null : (Properties) parameters.get("init.properties")); } @Override public boolean isInitialized() { synchronized (lock) { return initialized; } } @Override public boolean start() { return isInitialized(); } @Override public boolean stop() { // Nothing to do here. return true; } @Override public int getRunningTaskCount() { if (!isInitialized()) { return -1; } String[] names = getTaskNames(); int count = 0; try { for (String name : names) { synchronized (lock) { if (taskManager == null) { logger.warn("#getRunningTaskCount Could not determine the number of running tasks. Task manager is not available."); return -1; } if (taskManager.getTaskState(name) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.NORMAL)) { ++count; } } } } catch (Exception e) { logger.error("Cannot return running task count. Error: " + e.getLocalizedMessage(), e); } return count; } public List<String> getRunningTaskList() { if (!isInitialized()) { return null; } String[] names = getTaskNames(); List<String> runningTaskList = new ArrayList<String>(); try { for (String name : names) { synchronized (lock) { if (taskManager.getTaskState(name) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.NORMAL)) { runningTaskList.add(name); } } } } catch (Exception e) { logger.error("Cannot return running task list. Error: " + e.getLocalizedMessage(), e); } return runningTaskList; } @Override public boolean isTaskRunning(Object o) { if (!isInitialized()) { return false; } String taskName; if (o instanceof String) { taskName = (String) o; } else { return false; } synchronized (lock) { if (taskManager == null) { logger.warn("#isTaskRunning Could not determine the state of the task [" + taskName + "]. Task manager is not available."); return false; } try { return taskManager.getTaskState(taskName) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.NORMAL); } catch (Exception e) { logger.error("Cannot return task status [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } } return false; } @Override public boolean setProperties(Map<String, Object> properties) { if (properties == null) { return false; } for (String key : properties.keySet()) { synchronized (lock) { this.properties.put(key, properties.get(key)); } } return true; } @Override public boolean setProperty(String name, Object property) { if (name == null) { return false; } synchronized (lock) { properties.put(name, property); } return true; } @Override public Object getProperty(String name) { if (name == null) { return null; } synchronized (lock) { return properties.get(name); } } @Override public void setName(String name) { this.name = name; } @Override public String getName() { return name; } @Override public String getProviderClass() { return this.getClass().getName(); } @Override public Properties getConfigurationProperties() { synchronized (lock) { return configProperties; } } @Override public void setConfigurationProperties(Properties properties) { if (properties == null) { return; } synchronized (lock) { configProperties.putAll(properties); } } private org.wso2.carbon.ntask.core.TaskManager getTaskManager(boolean system) throws Exception { TaskService taskService = NtaskService.getTaskService(); if (taskService == null) { return null; } return taskService.getTaskManager(Constants.TASK_TYPE_ESB); } private int getCurrentTenantId() { return CarbonContext.getThreadLocalCarbonContext().getTenantId(); } public static int tenantId() { return CarbonContext.getThreadLocalCarbonContext().getTenantId(); } @Override public void invoke() { //Initialize the Task Manager after server is started init(null); } private String taskId(TaskDescription description) { return "[NTask::" + getCurrentTenantId() + "::" + description.getName() + "]"; } private String managerId() { return "[NTaskTaskManager::" + getCurrentTenantId() + " ::" + this.hashCode() + "]"; } @Override public void addObserver(TaskManagerObserver o) { if (observers.contains(o)) { return; } observers.add(o); } @Override public boolean isTaskDeactivated(String taskName) { if (!isInitialized()) { return false; } synchronized (lock) { if (taskManager == null) { logger.warn("#isTaskRunning Could not determine the state of the task [" + taskName + "]. Task manager is not available."); return false; } try { return taskManager.getTaskState(taskName) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.PAUSED); } catch (Exception e) { /* * This fix was given to avoid error messages printing * while server shutdowns in cluster mode when MP is running. * This is related to the issue ESBJAVA-4061. */ if (logger.isDebugEnabled()) { logger.debug("Cannot return task status [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } } } return false; } @Override public boolean isTaskBlocked(String taskName) { if (!isInitialized()) { return false; } synchronized (lock) { if (taskManager == null) { logger.warn("#isTaskRunning Could not determine the state of the task [" + taskName + "]. Task manager is not available."); return false; } try { return taskManager.getTaskState(taskName) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.BLOCKED); } catch (Exception e) { logger.error("Cannot return task status [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } } return false; } @Override public boolean isTaskRunning(String taskName) { if (!isInitialized()) { return false; } synchronized (lock) { if (taskManager == null) { logger.warn("#isTaskRunning Could not determine the state of the task [" + taskName + "]. Task manager is not available."); return false; } try { return taskManager.getTaskState(taskName) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.NORMAL); } catch (Exception e) { logger.error("Cannot return task status [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } } return false; } public boolean isTaskExist(String taskName) { if (!isInitialized()) { return false; } synchronized (lock) { if (taskManager == null) { logger.warn("#isTaskExist Could not determine the state of the task [" + taskName + "]. Task manager is not available."); return false; } try { return !taskManager.getTaskState(taskName) .equals(org.wso2.carbon.ntask.core.TaskManager.TaskState.NONE); } catch (Exception e) { logger.error("Cannot return task status [" + taskName + "]. Error: " + e.getLocalizedMessage(), e); } } return false; } private void updateAndCleanupObservers() { Iterator<TaskManagerObserver> i = observers.iterator(); while (i.hasNext()) { TaskManagerObserver observer = i.next(); observer.update(); i.remove(); } } private boolean queueTask(TaskDescription description) { synchronized (taskQueueLock) { logger.debug("#queueTask Queuing task " + taskId(description)) ; if (!taskQueue.contains(description)) { return taskQueue.add(description); } } return false; } private boolean removeTask(TaskDescription description) { synchronized (taskQueueLock) { logger.debug("#removeTask removing task " + taskId(description)) ; return taskQueue.remove(description); } } private Object[] pendingTasks() { synchronized (taskQueueLock) { return taskQueue.toArray(); } } @Override public void sendClusterMessage(Callable<Void> callable) { if (taskManager instanceof ClusteredTaskManager) { try { IExecutorService executorService = ((ClusteredTaskManager) taskManager).getClusterComm() .getHazelcast() .getExecutorService(NTASK_P2P_COMM_EXECUTOR); executorService.submitToAllMembers(callable); } catch (TaskException e) { logger.error("Can not submit a cluster message.", e); } } } }