/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.schedule;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.lifecycle.LifecyclePriorities;
import org.jboss.soa.esb.lifecycle.LifecycleResource;
import org.jboss.soa.esb.lifecycle.LifecycleResourceException;
import org.jboss.soa.esb.lifecycle.LifecycleResourceFactory;
import org.jboss.soa.esb.lifecycle.LifecycleResourceManager;
import org.jboss.soa.esb.util.ClassUtil;
import org.quartz.JobDetail;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
/**
* Scheduler resource tied to the lifecycle.
*/
public class SchedulerResource
{
/**
* The logger for this class.
*/
private static Logger LOGGER = Logger.getLogger(SchedulerResource.class);
/**
* The lifecycle resource factory.
*/
private static final LifecycleResourceFactory<SchedulerResource> lifecycleSchedulerFactory = new SchedulerFactory() ;
/**
* Lifecycle schedulers.
*/
private static final LifecycleResource<SchedulerResource> lifecycleSchedulerResource =
new LifecycleResource<SchedulerResource>(lifecycleSchedulerFactory, LifecyclePriorities.SCHEDULE_RESOURCE_PRIORITY) ;
/**
* The instance name property.
*/
public static final String INSTANCE_NAME = "org.quartz.scheduler.instanceName" ;
/**
* The thread name property.
*/
public static final String THREAD_NAME = "org.quartz.scheduler.threadName" ;
/**
* The thread count property.
*/
public static final String THREAD_COUNT = "org.quartz.threadPool.threadCount" ;
/**
* The quartz scheduler associated with this resource.
*/
private Scheduler scheduler ;
private SchedulerResource()
{
}
/**
* Start a trigger on the contextualised resource.
* @param trigger The trigger to enable.
* @param jobDetail The details of the job.
* @param properties The properties for the scheduler.
* @throws SchedulingException For any errors.
*
* Note that there is only one scheduler in force per scheduled esb artifact and, therefore,
* the first invocation will create the scheduler. We may support multiple schedulers at a later
* point in time.
*/
synchronized void start(final Trigger trigger, final JobDetail jobDetail, final Properties properties)
throws SchedulingException
{
initScheduler(properties) ;
try
{
try
{
scheduler.scheduleJob(jobDetail, trigger) ;
}
catch (final ObjectAlreadyExistsException oaee)
{
scheduler.resumeTrigger(trigger.getName(), trigger.getGroup()) ;
}
}
catch (final SchedulerException se)
{
throw new SchedulingException("Failed to start scheduled job", se) ;
}
}
/**
* Pause a trigger on the contextualised resource.
* @param trigger The trigger to pause.
* @throws SchedulingException For any errors.
*/
synchronized void pause(final Trigger trigger)
throws SchedulingException
{
if (scheduler != null)
{
try
{
if (scheduler.isShutdown())
{
throw new SchedulingException("Scheduler has been shutdown") ;
}
scheduler.pauseTrigger(trigger.getName(), trigger.getGroup()) ;
}
catch (final SchedulerException se)
{
throw new SchedulingException("Failed to pause scheduled job", se) ;
}
}
}
/**
* Destroy a trigger on the contextualised resource.
* @param trigger The trigger to destroy.
* @throws SchedulingException For any errors.
*/
synchronized void destroy(final Trigger trigger)
throws SchedulingException
{
if (scheduler != null)
{
try
{
if (scheduler.isShutdown())
{
throw new SchedulingException("Scheduler has been shutdown") ;
}
scheduler.unscheduleJob(trigger.getName(), trigger.getGroup()) ;
}
catch (final SchedulerException se)
{
throw new SchedulingException("Failed to destroy scheduled job", se) ;
}
}
}
/**
* Shutdown the contextualised resource.
* @throws SchedulingException For any errors.
*/
synchronized void shutdown()
throws SchedulingException
{
if (scheduler != null)
{
try
{
if (!scheduler.isShutdown())
{
scheduler.shutdown() ;
}
}
catch (final SchedulerException se)
{
throw new SchedulingException("Failed to shutdown scheduler", se) ;
}
}
}
/**
* Initialise the scheduler if necessary.
* @param properties The properties used to create a scheduler.
*/
private void initScheduler(final Properties properties)
throws SchedulingException
{
if (scheduler == null)
{
final InputStream quartzProperties = ClassUtil.getResourceAsStream("quartz.properties", SchedulerResource.class) ;
if(quartzProperties == null)
{
throw new SchedulingException("Failed to locate the default scheduling properties") ;
}
final Properties defaultProperties = new Properties();
try
{
defaultProperties.load(quartzProperties) ;
}
catch (final IOException ioe)
{
throw new SchedulingException("Failed to load the default scheduling properties") ;
}
if(properties != null)
{
defaultProperties.putAll(properties) ;
}
final String name = "ESBScheduler:" + getDeploymentName() ;
defaultProperties.put(INSTANCE_NAME, name) ;
defaultProperties.put(THREAD_NAME, name) ;
if (!defaultProperties.containsKey(THREAD_COUNT))
{
defaultProperties.put(THREAD_COUNT, "1") ;
}
final Scheduler scheduler ;
try
{
scheduler = new StdSchedulerFactory(defaultProperties).getScheduler();
scheduler.start() ;
}
catch (final SchedulerException se)
{
throw new SchedulingException("Failed to initialise the scheduler", se) ;
}
this.scheduler = scheduler ;
}
}
/**
* Create a name associated with this deployment.
* @return The deployment name.
*/
private String getDeploymentName()
{
final LifecycleResourceManager lifecycleResourceManager = LifecycleResourceManager.getSingleton() ;
final String[] associatedDeployments = lifecycleResourceManager.getAssociatedDeployments() ;
final String deployment ;
if ((associatedDeployments != null) && (associatedDeployments.length == 1))
{
deployment = associatedDeployments[0] ;
}
else
{
deployment = lifecycleResourceManager.getIdentity() ;
}
return deployment ;
}
/**
* Get the scheduler resource.
* @return The scheduler resource.
* @throws LifecycleResourceException for errors acquiring the resource.
*/
static SchedulerResource getSchedulerResource()
throws SchedulingException
{
try
{
return lifecycleSchedulerResource.getLifecycleResource() ;
}
catch (final LifecycleResourceException lre)
{
throw new SchedulingException("Failed to obtain the contextualised scheduler resource", lre) ;
}
}
/**
* The lifecycle resource factory
* @author kevin
*/
private static class SchedulerFactory implements LifecycleResourceFactory<SchedulerResource>
{
/**
* Create a resource object which will be associated with the specified lifecycle identity.
* @param lifecycleIdentity The associated lifecycle identity.
* @return The lifecycle resource
* @throws LifecycleResourceException for errors during construction.
*/
public SchedulerResource createLifecycleResource(final String lifecycleIdentity)
throws LifecycleResourceException
{
return new SchedulerResource() ;
}
/**
* Destroy a resource object which is associated with the specified lifecycle identity.
* @param resource The lifecycle resource.
* @param lifecycleIdentity The associated lifecycle identity.
* @return The lifecycle resource.
* @throws LifecycleResourceException for errors during destroy.
*/
public void destroyLifecycleResource(final SchedulerResource resource, final String lifecycleIdentity)
throws LifecycleResourceException
{
LOGGER.debug("Shutting down scheduler for identity " + lifecycleIdentity) ;
try
{
resource.shutdown() ;
}
catch (final SchedulingException se)
{
throw new LifecycleResourceException("Failed to shutdown the contextualised scheduler resource") ;
}
}
}
}