1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.batch.core.repository.support;
18
19 import org.aopalliance.intercept.MethodInterceptor;
20 import org.aopalliance.intercept.MethodInvocation;
21 import org.springframework.aop.framework.ProxyFactory;
22 import org.springframework.aop.support.DefaultPointcutAdvisor;
23 import org.springframework.aop.support.NameMatchMethodPointcut;
24 import org.springframework.batch.core.repository.JobRepository;
25 import org.springframework.batch.core.repository.dao.ExecutionContextDao;
26 import org.springframework.batch.core.repository.dao.JobExecutionDao;
27 import org.springframework.batch.core.repository.dao.JobInstanceDao;
28 import org.springframework.batch.core.repository.dao.StepExecutionDao;
29 import org.springframework.batch.support.PropertiesConverter;
30 import org.springframework.beans.factory.FactoryBean;
31 import org.springframework.beans.factory.InitializingBean;
32 import org.springframework.transaction.PlatformTransactionManager;
33 import org.springframework.transaction.interceptor.TransactionInterceptor;
34 import org.springframework.transaction.support.TransactionSynchronizationManager;
35 import org.springframework.util.Assert;
36
37
38
39
40
41
42
43
44
45
46
47
48
49 @SuppressWarnings("rawtypes")
50 public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, InitializingBean {
51
52 private PlatformTransactionManager transactionManager;
53
54 private ProxyFactory proxyFactory;
55
56 private String isolationLevelForCreate = DEFAULT_ISOLATION_LEVEL;
57
58 private boolean validateTransactionState = true;
59
60
61
62
63 private static final String DEFAULT_ISOLATION_LEVEL = "ISOLATION_SERIALIZABLE";
64
65
66
67
68 protected abstract JobInstanceDao createJobInstanceDao() throws Exception;
69
70
71
72
73 protected abstract JobExecutionDao createJobExecutionDao() throws Exception;
74
75
76
77
78 protected abstract StepExecutionDao createStepExecutionDao() throws Exception;
79
80
81
82
83 protected abstract ExecutionContextDao createExecutionContextDao() throws Exception;
84
85
86
87
88
89
90
91 @Override
92 public Class<JobRepository> getObjectType() {
93 return JobRepository.class;
94 }
95
96 @Override
97 public boolean isSingleton() {
98 return true;
99 }
100
101
102
103
104
105
106
107
108
109 public void setValidateTransactionState(boolean validateTransactionState) {
110 this.validateTransactionState = validateTransactionState;
111 }
112
113
114
115
116
117
118
119
120
121
122
123
124 public void setIsolationLevelForCreate(String isolationLevelForCreate) {
125 this.isolationLevelForCreate = isolationLevelForCreate;
126 }
127
128
129
130
131
132 public void setTransactionManager(PlatformTransactionManager transactionManager) {
133 this.transactionManager = transactionManager;
134 }
135
136
137
138
139
140
141
142 public PlatformTransactionManager getTransactionManager() {
143 return transactionManager;
144 }
145
146
147
148
149
150
151
152 public JobRepository getJobRepository() throws Exception {
153 return (JobRepository) getObject();
154 }
155
156 private void initializeProxy() throws Exception {
157 if (proxyFactory == null) {
158 proxyFactory = new ProxyFactory();
159 TransactionInterceptor advice = new TransactionInterceptor(transactionManager,
160 PropertiesConverter.stringToProperties("create*=PROPAGATION_REQUIRES_NEW,"
161 + isolationLevelForCreate + "\ngetLastJobExecution*=PROPAGATION_REQUIRES_NEW,"
162 + isolationLevelForCreate + "\n*=PROPAGATION_REQUIRED"));
163 if (validateTransactionState) {
164 DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(new MethodInterceptor() {
165 @Override
166 public Object invoke(MethodInvocation invocation) throws Throwable {
167 if (TransactionSynchronizationManager.isActualTransactionActive()) {
168 throw new IllegalStateException(
169 "Existing transaction detected in JobRepository. "
170 + "Please fix this and try again (e.g. remove @Transactional annotations from client).");
171 }
172 return invocation.proceed();
173 }
174 });
175 NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
176 pointcut.addMethodName("create*");
177 advisor.setPointcut(pointcut);
178 proxyFactory.addAdvisor(advisor);
179 }
180 proxyFactory.addAdvice(advice);
181 proxyFactory.setProxyTargetClass(false);
182 proxyFactory.addInterface(JobRepository.class);
183 proxyFactory.setTarget(getTarget());
184 }
185 }
186
187 @Override
188 public void afterPropertiesSet() throws Exception {
189 Assert.notNull(transactionManager, "TransactionManager must not be null.");
190
191 initializeProxy();
192 }
193
194 private Object getTarget() throws Exception {
195 return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(),
196 createExecutionContextDao());
197 }
198
199 @Override
200 public Object getObject() throws Exception {
201 if (proxyFactory == null) {
202 afterPropertiesSet();
203 }
204 return proxyFactory.getProxy();
205 }
206
207 }