1 | /* |
2 | * Copyright 2006-2007 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 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException { |
92 | if (beanFactory instanceof DefaultListableBeanFactory) { |
93 | this.beanFactory = (DefaultListableBeanFactory) beanFactory; |
94 | } |
95 | } |
96 | |
97 | /** |
98 | * Make sure the registry is set before use. |
99 | * |
100 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() |
101 | */ |
102 | public void afterPropertiesSet() throws Exception { |
103 | Assert.notNull(jobRegistry, "JobRegistry must not be null"); |
104 | } |
105 | |
106 | /** |
107 | * De-register all the {@link Job} instances that were regsistered by this |
108 | * post processor. |
109 | * @see org.springframework.beans.factory.DisposableBean#destroy() |
110 | */ |
111 | public void destroy() throws Exception { |
112 | for (String name : jobNames) { |
113 | logger.debug("Unregistering job: " + name); |
114 | jobRegistry.unregister(name); |
115 | } |
116 | jobNames.clear(); |
117 | } |
118 | |
119 | /** |
120 | * If the bean is an instance of {@link Job} then register it. |
121 | * @throws FatalBeanException if there is a {@link DuplicateJobException}. |
122 | * |
123 | * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, |
124 | * java.lang.String) |
125 | */ |
126 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { |
127 | if (bean instanceof Job) { |
128 | Job job = (Job) bean; |
129 | try { |
130 | String groupName = this.groupName; |
131 | if (beanFactory != null && beanFactory.containsBean(beanName)) { |
132 | groupName = getGroupName(beanFactory.getBeanDefinition(beanName), job); |
133 | } |
134 | job = groupName==null ? job : new GroupAwareJob(groupName, job); |
135 | ReferenceJobFactory jobFactory = new ReferenceJobFactory(job); |
136 | String name = jobFactory.getJobName(); |
137 | logger.debug("Registering job: " + name); |
138 | jobRegistry.register(jobFactory); |
139 | jobNames.add(name); |
140 | } |
141 | catch (DuplicateJobException e) { |
142 | throw new FatalBeanException("Cannot register job configuration", e); |
143 | } |
144 | return job; |
145 | } |
146 | return bean; |
147 | } |
148 | |
149 | /** |
150 | * Determine a group name for the job to be registered. Default |
151 | * implementation just returns the {@link #setGroupName(String) groupName} |
152 | * configured. Provides an extension point for specialised subclasses. |
153 | * |
154 | * @param beanDefinition the bean definition for the job |
155 | * @param job the job |
156 | * @return a group name for the job (or null if not needed) |
157 | */ |
158 | protected String getGroupName(BeanDefinition beanDefinition, Job job) { |
159 | return groupName; |
160 | } |
161 | |
162 | /** |
163 | * Do nothing. |
164 | * |
165 | * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, |
166 | * java.lang.String) |
167 | */ |
168 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { |
169 | return bean; |
170 | } |
171 | } |