package org.apache.synapse.startup.quartz;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import org.apache.axiom.om.OMElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.ManagedLifecycle;
import org.apache.synapse.commons.util.PropertyHelper;
import org.apache.synapse.core.SynapseEnvironment;
import org.apache.synapse.task.DefaultTaskJobDetailFactory;
import org.apache.synapse.task.DefaultTaskTriggerFactory;
import org.apache.synapse.task.SynapseTaskException;
import org.apache.synapse.task.Task;
import org.apache.synapse.task.TaskConstants;
import org.apache.synapse.task.TaskDescription;
import org.apache.synapse.task.TaskJobDetailFactory;
import org.apache.synapse.task.TaskManager;
import org.apache.synapse.task.TaskManagerObserver;
import org.apache.synapse.task.TaskTriggerFactory;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzTaskManager implements TaskManager {
private static final Log logger = LogFactory.getLog(QuartzTaskManager.class.getName());
private static final Object lock = new Object();
/**
* scheduler instance
*/
private Scheduler scheduler;
/**
* Determines whether scheduler has been initialized and is ready to schedule a task or not.
*/
private boolean initialized = false;
/**
* Default trigger factory
*/
private TaskTriggerFactory triggerFactory = new DefaultTaskTriggerFactory();
/**
* Default job detail factory
*/
private TaskJobDetailFactory jobDetailFactory = new DefaultTaskJobDetailFactory();
/**
* Property look up key for get a quartz configuration
*/
public final static String QUARTZ_CONF = "quartz.conf";
private String name;
protected final Properties configProperties = new Properties();
@Override
public boolean schedule(TaskDescription taskDescription) {
assertInitialized();
assertStarted();
if (taskDescription == null) {
throw new SynapseTaskException("Task Description cannot be found", logger);
}
Trigger trigger;
JobDetail jobDetail;
synchronized (lock) {
if (triggerFactory == null) {
throw new SynapseTaskException("TriggerFactory cannot be found", logger);
}
if (jobDetailFactory == null) {
throw new SynapseTaskException("JobDetailFactory cannot be found", logger);
}
trigger = triggerFactory.createTrigger(taskDescription);
if (trigger == null) {
throw new SynapseTaskException("Trigger cannot be created from : "
+ taskDescription, logger);
}
jobDetail = jobDetailFactory.createJobDetail(taskDescription,
taskDescription.getResources(), SimpleQuartzJob.class);
if (jobDetail == null) {
throw new SynapseTaskException("JobDetail cannot be created from : " + taskDescription +
" and job class " + taskDescription.getTaskImplClassName(), logger);
}
}
Object clsInstance = taskDescription.getResource(TaskDescription.INSTANCE);
if (clsInstance == null) {
String className = (String) taskDescription.getProperty(TaskDescription.CLASSNAME);
try {
clsInstance = Class.forName(className).newInstance();
if (clsInstance instanceof ManagedLifecycle) {
Object se = properties.get(TaskConstants.SYNAPSE_ENV);
if (!(se instanceof SynapseEnvironment)) {
return false;
}
((ManagedLifecycle) clsInstance).init((SynapseEnvironment) se);
}
for (Object property : taskDescription.getXmlProperties()) {
OMElement prop = (OMElement) property;
logger.debug("Found Property : " + prop.toString());
PropertyHelper.setStaticProperty(prop, clsInstance);
}
} catch (ClassNotFoundException e) {
logger.error("Could not schedule task[" + name + "].", e);
return false;
} catch (InstantiationException e) {
logger.error("Could not schedule task[" + name + "].", e);
return false;
} catch (IllegalAccessException e) {
logger.error("Could not schedule task[" + name + "].", e);
return false;
}
}
if (!(clsInstance instanceof Task)) {
logger.error("Could not schedule task[" + name + "]. Cannot load class " + "org.apache.synapse.startup.quartz.SimpleQuartzJob");
return false;
}
jobDetail.getJobDataMap().put(TaskDescription.INSTANCE, clsInstance);
jobDetail.getJobDataMap().put(TaskDescription.CLASSNAME, clsInstance.getClass().toString());
jobDetail.getJobDataMap().put(TaskConstants.SYNAPSE_ENV, getProperty(TaskConstants.SYNAPSE_ENV));
try {
if (logger.isDebugEnabled()) {
logger.debug("scheduling job : " + jobDetail + " with trigger " + trigger);
}
if (taskDescription.getCount() != 0 && !isTaskRunning(jobDetail.getKey())) {
try {
synchronized (lock) {
scheduler.scheduleJob(jobDetail, trigger);
}
} catch (ObjectAlreadyExistsException e) {
logger.warn("did not schedule the job : " + jobDetail + ". the job is already running.");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("did not schedule the job : " + jobDetail + ". count is zero.");
}
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error scheduling job : " + jobDetail
+ " with trigger " + trigger);
}
logger.info("Scheduled task [" + taskDescription.getName() + "::" + taskDescription.getTaskGroup() + "]");
return true;
}
@Override
public boolean reschedule(String name, TaskDescription taskDescription) {
logger.error("reschedule not supported. Task name: " + name);
return false;
}
@Override
public boolean delete(String nameGroup) {
if (nameGroup == null) {
return false;
}
assertInitialized();
assertStarted();
String list[] = nameGroup.split("::");
String name = list[0];
String group = list[1];
if (name == null || "".equals(name)) {
throw new SynapseTaskException("Task name is null", logger);
}
if (group == null || "".equals(group)) {
group = TaskDescription.DEFAULT_GROUP;
if (logger.isDebugEnabled()) {
logger.debug("Task group is null or empty , using default group :"
+ TaskDescription.DEFAULT_GROUP);
}
}
boolean deleteResult;
try {
synchronized (lock) {
deleteResult = scheduler.deleteJob(new JobKey(name, group));
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Cannot delete task [" + name + "::" + group + "]");
}
logger.debug("Deleted task [" + name + "::" + group + "] [" + deleteResult + "]");
return true;
}
@Override
public boolean pause(String name) {
logger.error("pause not supported. Task name : " + name);
return false;
}
@Override
public boolean pauseAll() {
try {
assertInitialized();
assertStarted();
synchronized (lock) {
scheduler.pauseAll();
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error pausing tasks ", e, logger);
}
return true;
}
@Override
public boolean resume(String name) {
return false;
}
@Override
public boolean resumeAll() {
try {
assertInitialized();
assertStarted();
synchronized (lock) {
scheduler.resumeAll();
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error resuming tasks ", e, logger);
}
return true;
}
@Override
public TaskDescription getTask(String name) {
return null;
}
@Override
public String[] getTaskNames() {
return new String[0];
}
@Override
public boolean init(Properties properties) {
StdSchedulerFactory sf = new StdSchedulerFactory();
if (properties != null) {
String quartzConf = properties.getProperty(QUARTZ_CONF);
try {
if (quartzConf != null && !"".equals(quartzConf)) {
if (logger.isDebugEnabled()) {
logger.debug("Initiating a Scheduler with configuration : " + quartzConf);
}
sf.initialize(quartzConf);
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error initiating scheduler factory "
+ sf + "with configuration loaded from " + quartzConf, e, logger);
}
}
try {
synchronized (lock) {
if (name != null) {
scheduler = sf.getScheduler(name);
}
if (scheduler == null) {
scheduler = sf.getScheduler();
}
initialized = true;
logger.info("initialized");
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error getting a scheduler instance form scheduler" +
" factory " + sf, e, logger);
}
return true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public boolean start() {
assertInitialized();
try {
synchronized (lock) {
if (!scheduler.isStarted()) {
if (logger.isDebugEnabled()) {
logger.debug("Starting a Scheduler : [ " + scheduler.getMetaData() + " ]");
}
scheduler.start();
}
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error starting scheduler ", e, logger);
}
return true;
}
@Override
public boolean stop() {
if (isInitialized()) {
try {
synchronized (lock) {
if (scheduler != null && scheduler.isStarted()) {
if (logger.isDebugEnabled()) {
logger.debug("ShuttingDown Task Scheduler : " + scheduler.getMetaData());
}
scheduler.shutdown();
}
initialized = false;
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error ShuttingDown task scheduler ", e, logger);
}
}
return false;
}
@Override
public int getRunningTaskCount() {
int runningTasks = 0;
try {
synchronized (lock) {
if (scheduler != null) {
runningTasks = scheduler.getCurrentlyExecutingJobs().size();
}
}
} catch (SchedulerException e) {
logger.error("Error querying currently executing jobs", e);
}
return runningTasks;
}
@Override
public boolean isTaskRunning(Object taskKey) {
if (!(taskKey instanceof JobKey)) {
return false;
}
try {
List<JobExecutionContext> currentJobs;
synchronized (lock) {
currentJobs = this.scheduler.getCurrentlyExecutingJobs();
}
JobKey currentJobKey;
for (JobExecutionContext jobCtx : currentJobs) {
currentJobKey = jobCtx.getJobDetail().getKey();
if (currentJobKey.compareTo((JobKey) taskKey) == 0) {
logger.warn("the job is already running");
return true;
}
}
} catch (SchedulerException e) {
return false;
}
return false;
}
private Map<String, Object> properties = new HashMap<String, Object>(5);
@Override
public boolean setProperties(Map<String, Object> properties) {
for (String key : properties.keySet()) {
synchronized (lock) {
this.properties.put(key, properties.get(key));
}
}
return true;
}
@Override
public boolean setProperty(String name, Object property) {
synchronized (lock) {
if ("Q_TASK_TRIGGER_FACTORY".equals(name) && (property instanceof TaskTriggerFactory)) {
triggerFactory = (TaskTriggerFactory) property;
}
if ("Q_TASK_JOB_DETAIL_FACTORY".equals(name) && (property instanceof TaskJobDetailFactory)) {
jobDetailFactory = (TaskJobDetailFactory) property;
}
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) {
synchronized (lock) {
this.configProperties.putAll(properties);
}
}
private void assertInitialized() {
synchronized (lock) {
if (!initialized) {
throw new SynapseTaskException("Scheduler has not been initialled yet", logger);
}
}
}
private void assertStarted() {
try {
synchronized (lock) {
if (!scheduler.isStarted()) {
throw new SynapseTaskException("Scheduler has not been started yet", logger);
}
}
} catch (SchedulerException e) {
throw new SynapseTaskException("Error determine start state of the scheduler ", e, logger);
}
}
@Override
public void addObserver(TaskManagerObserver o) {
}
@Override
public boolean isTaskDeactivated(String taskName) {
return false;
}
@Override
public boolean isTaskBlocked(String taskName) {
return false;
}
@Override
public boolean isTaskRunning(String taskName) {
return false;
}
@Override
public void sendClusterMessage(Callable<Void> task) {
}
public boolean isTaskExist(String arg0) {
return false;
}
}