1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.batch.repeat.interceptor;
18
19 import org.aopalliance.intercept.MethodInterceptor;
20 import org.aopalliance.intercept.MethodInvocation;
21 import org.springframework.aop.ProxyMethodInvocation;
22 import org.springframework.batch.repeat.RepeatStatus;
23 import org.springframework.batch.repeat.RepeatCallback;
24 import org.springframework.batch.repeat.RepeatContext;
25 import org.springframework.batch.repeat.RepeatException;
26 import org.springframework.batch.repeat.RepeatOperations;
27 import org.springframework.batch.repeat.support.RepeatTemplate;
28 import org.springframework.util.Assert;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class RepeatOperationsInterceptor implements MethodInterceptor {
44
45 private RepeatOperations repeatOperations = new RepeatTemplate();
46
47
48
49
50
51
52
53 public void setRepeatOperations(RepeatOperations batchTempate) {
54 Assert.notNull(batchTempate, "'repeatOperations' cannot be null.");
55 this.repeatOperations = batchTempate;
56 }
57
58
59
60
61
62
63
64 @Override
65 public Object invoke(final MethodInvocation invocation) throws Throwable {
66
67 final ResultHolder result = new ResultHolder();
68
69 final boolean voidReturnType = Void.TYPE.equals(invocation.getMethod().getReturnType());
70 if (voidReturnType) {
71
72
73 result.setValue(new Object());
74 }
75
76 try {
77 repeatOperations.iterate(new RepeatCallback() {
78
79 @Override
80 public RepeatStatus doInIteration(RepeatContext context) throws Exception {
81 try {
82
83 MethodInvocation clone = invocation;
84 if (invocation instanceof ProxyMethodInvocation) {
85 clone = ((ProxyMethodInvocation) invocation).invocableClone();
86 }
87 else {
88 throw new IllegalStateException(
89 "MethodInvocation of the wrong type detected - this should not happen with Spring AOP, so please raise an issue if you see this exception");
90 }
91
92 Object value = clone.proceed();
93 if (voidReturnType) {
94 return RepeatStatus.CONTINUABLE;
95 }
96 if (!isComplete(value)) {
97
98 result.setValue(value);
99 return RepeatStatus.CONTINUABLE;
100 }
101 else {
102 result.setFinalValue(value);
103 return RepeatStatus.FINISHED;
104 }
105 }
106 catch (Throwable e) {
107 if (e instanceof Exception) {
108 throw (Exception) e;
109 }
110 else {
111 throw new RepeatOperationsInterceptorException("Unexpected error in batch interceptor", e);
112 }
113 }
114 }
115
116 });
117 }
118 catch (Throwable t) {
119
120 throw t;
121 }
122
123 if (result.isReady()) {
124 return result.getValue();
125 }
126
127
128 throw new IllegalStateException("No result available for attempted repeat call to " + invocation
129 + ". The invocation was never called, so maybe there is a problem with the completion policy?");
130 }
131
132
133
134
135
136 private boolean isComplete(Object result) {
137 return result == null || (result instanceof Boolean) && !((Boolean) result).booleanValue();
138 }
139
140
141
142
143
144
145
146
147 private static class RepeatOperationsInterceptorException extends RepeatException {
148
149
150
151
152 public RepeatOperationsInterceptorException(String message, Throwable e) {
153 super(message, e);
154 }
155 }
156
157
158
159
160
161
162
163 private static class ResultHolder {
164 private Object value = null;
165
166 private boolean ready = false;
167
168
169
170
171
172 public void setValue(Object value) {
173 this.ready = true;
174 this.value = value;
175 }
176
177
178
179
180 public void setFinalValue(Object value) {
181 if (ready) {
182
183
184 return;
185 }
186 setValue(value);
187 }
188
189
190
191
192
193 public Object getValue() {
194 return value;
195 }
196
197
198
199
200 public boolean isReady() {
201 return ready;
202 }
203 }
204
205 }