| 1 | /* |
| 2 | * Copyright 2006-2013 the original author or authors. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | package org.springframework.batch.core.configuration.support; |
| 17 | |
| 18 | import java.util.Collection; |
| 19 | import java.util.HashSet; |
| 20 | |
| 21 | import org.apache.commons.logging.Log; |
| 22 | import org.apache.commons.logging.LogFactory; |
| 23 | import org.springframework.batch.core.Job; |
| 24 | import org.springframework.batch.core.configuration.DuplicateJobException; |
| 25 | import org.springframework.batch.core.configuration.JobLocator; |
| 26 | import org.springframework.batch.core.configuration.JobRegistry; |
| 27 | import org.springframework.beans.BeansException; |
| 28 | import org.springframework.beans.FatalBeanException; |
| 29 | import org.springframework.beans.factory.BeanFactory; |
| 30 | import org.springframework.beans.factory.BeanFactoryAware; |
| 31 | import org.springframework.beans.factory.DisposableBean; |
| 32 | import org.springframework.beans.factory.InitializingBean; |
| 33 | import org.springframework.beans.factory.config.BeanDefinition; |
| 34 | import org.springframework.beans.factory.config.BeanPostProcessor; |
| 35 | import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
| 36 | import org.springframework.util.Assert; |
| 37 | |
| 38 | /** |
| 39 | * A {@link BeanPostProcessor} that registers {@link Job} beans with a |
| 40 | * {@link JobRegistry}. Include a bean of this type along with your job |
| 41 | * configuration, and use the same {@link JobRegistry} as a {@link JobLocator} |
| 42 | * when you need to locate a {@link Job} to launch. |
| 43 | * |
| 44 | * @author Dave Syer |
| 45 | * |
| 46 | */ |
| 47 | public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean, |
| 48 | DisposableBean { |
| 49 | |
| 50 | private static Log logger = LogFactory.getLog(JobRegistryBeanPostProcessor.class); |
| 51 | |
| 52 | // It doesn't make sense for this to have a default value... |
| 53 | private JobRegistry jobRegistry = null; |
| 54 | |
| 55 | private Collection<String> jobNames = new HashSet<String>(); |
| 56 | |
| 57 | private String groupName = null; |
| 58 | |
| 59 | private DefaultListableBeanFactory beanFactory; |
| 60 | |
| 61 | /** |
| 62 | * The group name for jobs registered by this component. Optional (defaults |
| 63 | * to null, which means that jobs are registered with their bean names). |
| 64 | * Useful where there is a hierarchy of application contexts all |
| 65 | * contributing to the same {@link JobRegistry}: child contexts can then |
| 66 | * define an instance with a unique group name to avoid clashes between job |
| 67 | * names. |
| 68 | * |
| 69 | * @param groupName the groupName to set |
| 70 | */ |
| 71 | public void setGroupName(String groupName) { |
| 72 | this.groupName = groupName; |
| 73 | } |
| 74 | |
| 75 | /** |
| 76 | * Injection setter for {@link JobRegistry}. |
| 77 | * |
| 78 | * @param jobRegistry the jobConfigurationRegistry to set |
| 79 | */ |
| 80 | public void setJobRegistry(JobRegistry jobRegistry) { |
| 81 | this.jobRegistry = jobRegistry; |
| 82 | } |
| 83 | |
| 84 | /* |
| 85 | * (non-Javadoc) |
| 86 | * |
| 87 | * @see |
| 88 | * org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org |
| 89 | * .springframework.beans.factory.BeanFactory) |
| 90 | */ |
| 91 | @Override |
| 92 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException { |
| 93 | if (beanFactory instanceof DefaultListableBeanFactory) { |
| 94 | this.beanFactory = (DefaultListableBeanFactory) beanFactory; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Make sure the registry is set before use. |
| 100 | * |
| 101 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() |
| 102 | */ |
| 103 | @Override |
| 104 | public void afterPropertiesSet() throws Exception { |
| 105 | Assert.notNull(jobRegistry, "JobRegistry must not be null"); |
| 106 | } |
| 107 | |
| 108 | /** |
| 109 | * De-register all the {@link Job} instances that were regsistered by this |
| 110 | * post processor. |
| 111 | * @see org.springframework.beans.factory.DisposableBean#destroy() |
| 112 | */ |
| 113 | @Override |
| 114 | public void destroy() throws Exception { |
| 115 | for (String name : jobNames) { |
| 116 | logger.debug("Unregistering job: " + name); |
| 117 | jobRegistry.unregister(name); |
| 118 | } |
| 119 | jobNames.clear(); |
| 120 | } |
| 121 | |
| 122 | /** |
| 123 | * If the bean is an instance of {@link Job} then register it. |
| 124 | * @throws FatalBeanException if there is a {@link DuplicateJobException}. |
| 125 | * |
| 126 | * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, |
| 127 | * java.lang.String) |
| 128 | */ |
| 129 | @Override |
| 130 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { |
| 131 | if (bean instanceof Job) { |
| 132 | Job job = (Job) bean; |
| 133 | try { |
| 134 | String groupName = this.groupName; |
| 135 | if (beanFactory != null && beanFactory.containsBean(beanName)) { |
| 136 | groupName = getGroupName(beanFactory.getBeanDefinition(beanName), job); |
| 137 | } |
| 138 | job = groupName==null ? job : new GroupAwareJob(groupName, job); |
| 139 | ReferenceJobFactory jobFactory = new ReferenceJobFactory(job); |
| 140 | String name = jobFactory.getJobName(); |
| 141 | logger.debug("Registering job: " + name); |
| 142 | jobRegistry.register(jobFactory); |
| 143 | jobNames.add(name); |
| 144 | } |
| 145 | catch (DuplicateJobException e) { |
| 146 | throw new FatalBeanException("Cannot register job configuration", e); |
| 147 | } |
| 148 | return job; |
| 149 | } |
| 150 | return bean; |
| 151 | } |
| 152 | |
| 153 | /** |
| 154 | * Determine a group name for the job to be registered. Default |
| 155 | * implementation just returns the {@link #setGroupName(String) groupName} |
| 156 | * configured. Provides an extension point for specialised subclasses. |
| 157 | * |
| 158 | * @param beanDefinition the bean definition for the job |
| 159 | * @param job the job |
| 160 | * @return a group name for the job (or null if not needed) |
| 161 | */ |
| 162 | protected String getGroupName(BeanDefinition beanDefinition, Job job) { |
| 163 | return groupName; |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | * Do nothing. |
| 168 | * |
| 169 | * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, |
| 170 | * java.lang.String) |
| 171 | */ |
| 172 | @Override |
| 173 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { |
| 174 | return bean; |
| 175 | } |
| 176 | } |