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 | } |