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 | |
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.ExitStatus; |
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 | * A {@link MethodInterceptor} that can be used to automatically repeat calls to a method on a service. The injected |
32 | * {@link RepeatOperations} is used to control the completion of the loop. By default it will repeat until the target |
33 | * method returns null. Be careful when injecting a bespoke {@link RepeatOperations} that the loop will actually |
34 | * terminate, because the default policy for a vanilla {@link RepeatTemplate} will never complete if the return type of |
35 | * the target method is void (the value returned is always not-null, representing the {@link Void#TYPE}). |
36 | * |
37 | * @author Dave Syer |
38 | */ |
39 | public class RepeatOperationsInterceptor implements MethodInterceptor { |
40 | |
41 | private RepeatOperations repeatOperations = new RepeatTemplate(); |
42 | |
43 | /** |
44 | * Setter for the {@link RepeatOperations}. |
45 | * |
46 | * @param batchTempate |
47 | * @throws IllegalArgumentException if the argument is null. |
48 | */ |
49 | public void setRepeatOperations(RepeatOperations batchTempate) { |
50 | Assert.notNull(batchTempate, "'repeatOperations' cannot be null."); |
51 | this.repeatOperations = batchTempate; |
52 | } |
53 | |
54 | /** |
55 | * Invoke the proceeding method call repeatedly, according to the properties of the injected |
56 | * {@link RepeatOperations}. |
57 | * |
58 | * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation) |
59 | */ |
60 | public Object invoke(final MethodInvocation invocation) throws Throwable { |
61 | |
62 | repeatOperations.iterate(new RepeatCallback() { |
63 | |
64 | public ExitStatus doInIteration(RepeatContext context) throws Exception { |
65 | try { |
66 | |
67 | MethodInvocation clone = invocation; |
68 | if (invocation instanceof ProxyMethodInvocation) { |
69 | clone = ((ProxyMethodInvocation) invocation).invocableClone(); |
70 | } else { |
71 | throw new IllegalStateException( |
72 | "MethodInvocation of the wrong type detected - this should not happen with Spring AOP, so please raise an issue if you see this exception"); |
73 | } |
74 | |
75 | // N.B. discards return value if there is one |
76 | if (clone.getMethod().getReturnType().equals(Void.TYPE)) { |
77 | clone.proceed(); |
78 | return ExitStatus.CONTINUABLE; |
79 | } |
80 | return new ExitStatus(clone.proceed() != null); |
81 | } catch (Throwable e) { |
82 | if (e instanceof Exception) { |
83 | throw (Exception) e; |
84 | } else { |
85 | throw new RepeatException("Unexpected error in batch interceptor", e); |
86 | } |
87 | } |
88 | } |
89 | |
90 | }); |
91 | |
92 | return null; |
93 | } |
94 | |
95 | } |