001 /* 002 * Copyright 2008-2009 the original author or authors. 003 * The contents of this file are subject to the Mozilla Public License 004 * Version 1.1 (the "License"); you may not use this file except in 005 * compliance with the License. You may obtain a copy of the License at 006 * http://www.mozilla.org/MPL/ 007 * 008 * Software distributed under the License is distributed on an "AS IS" 009 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 010 * License for the specific language governing rights and limitations 011 * under the License. 012 */ 013 014 package com.mtgi.analytics.aop.config.v11; 015 016 import org.quartz.JobDetail; 017 import org.quartz.Scheduler; 018 import org.quartz.SchedulerException; 019 import org.quartz.Trigger; 020 import org.springframework.beans.MutablePropertyValues; 021 import org.springframework.beans.factory.BeanFactory; 022 import org.springframework.beans.factory.InitializingBean; 023 import org.springframework.beans.factory.config.BeanDefinition; 024 import org.springframework.beans.factory.config.BeanDefinitionHolder; 025 import org.springframework.beans.factory.support.BeanDefinitionBuilder; 026 import org.springframework.beans.factory.xml.ParserContext; 027 import org.springframework.scheduling.SchedulingException; 028 import org.springframework.scheduling.quartz.JobDetailAwareTrigger; 029 030 import com.mtgi.analytics.aop.config.TemplateBeanDefinitionParser; 031 032 /** 033 * Adds a trigger to a Quartz scheduler automatically after a bean factory is initialized. 034 * Note that the source of the scheduler and the trigger does not necessarily 035 * have to be the bean factory that contains this bean. This is intended to assist in 036 * processing of a {@link TemplateBeanDefinitionParser}, in which beans are 037 * defined in a source template factory and then promoted out into a target factory after 038 * transformation. 039 * 040 * @see TemplateBeanDefinitionParser 041 */ 042 public class SchedulerActivationPostProcessor implements InitializingBean { 043 044 private BeanFactory sourceFactory; 045 private String schedulerName; 046 private String triggerName; 047 048 public void setSourceFactory(BeanFactory sourceFactory) { 049 this.sourceFactory = sourceFactory; 050 } 051 052 public void setSchedulerName(String schedulerName) { 053 this.schedulerName = schedulerName; 054 } 055 056 public void setTriggerName(String triggerName) { 057 this.triggerName = triggerName; 058 } 059 060 public void afterPropertiesSet() throws Exception { 061 Scheduler scheduler = (Scheduler)sourceFactory.getBean(schedulerName, Scheduler.class); 062 Trigger trigger = (Trigger)sourceFactory.getBean(triggerName, Trigger.class); 063 try { 064 if (trigger instanceof JobDetailAwareTrigger) { 065 JobDetail job = ((JobDetailAwareTrigger)trigger).getJobDetail(); 066 scheduler.addJob(job, false); 067 } 068 scheduler.scheduleJob(trigger); 069 } catch (SchedulerException e) { 070 throw new SchedulingException("error scheduling trigger [" + trigger + "]", e); 071 } 072 } 073 074 /** 075 * Convenience method to register a {@link SchedulerActivationPostProcessor} in the given BeanFactory 076 * parse context with the given properties. 077 * @param parseContext the target bean factory in this context will have a {@link SchedulerActivationPostProcessor} registered 078 * @param sourceFactory the source for both the named scheduler and trigger instances 079 * @param schedulerName the name of the Quartz {@link Scheduler} in <code>sourceFactory</code> to use 080 * @param triggerName the name of the Quarty {@link Trigger} in <code>sourceFactory</code> that must be scheduled 081 */ 082 public static void registerPostProcessor(ParserContext parseContext, BeanFactory sourceFactory, String schedulerName, String triggerName) { 083 BeanDefinitionBuilder scheduleBootstrap = BeanDefinitionBuilder.rootBeanDefinition(SchedulerActivationPostProcessor.class); 084 scheduleBootstrap.addPropertyValue("sourceFactory", sourceFactory); 085 scheduleBootstrap.addPropertyValue("schedulerName", schedulerName); 086 scheduleBootstrap.addPropertyValue("triggerName", triggerName); 087 scheduleBootstrap.setLazyInit(false); 088 parseContext.getReaderContext().registerWithGeneratedName(scheduleBootstrap.getBeanDefinition()); 089 } 090 091 /** 092 * Convenience method to override a CronTrigger bean definition with the given cron expression 093 * and base name. 094 */ 095 public static void configureTriggerDefinition(BeanDefinition trigger, String cronExpression, String name) { 096 MutablePropertyValues props = trigger.getPropertyValues(); 097 if (cronExpression != null) { 098 props.removePropertyValue("cronExpression"); 099 props.addPropertyValue("cronExpression", cronExpression); 100 } 101 props.addPropertyValue("name", name + "_trigger"); 102 103 unwrapInnerBean(trigger, "jobDetail").getPropertyValues().addPropertyValue("name", name + "_job"); 104 } 105 106 public static BeanDefinition unwrapInnerBean(BeanDefinition parent, String property) { 107 Object value = parent.getPropertyValues().getPropertyValue(property).getValue(); 108 if (value == null) 109 return null; 110 if (value instanceof BeanDefinition) 111 return (BeanDefinition)value; 112 if (value instanceof BeanDefinitionHolder) 113 return ((BeanDefinitionHolder)value).getBeanDefinition(); 114 throw new IllegalArgumentException("Don't know how to convert " + value.getClass() + " into a BeanDefinition for property " + property); 115 } 116 117 }