EMMA Coverage Report (generated Thu May 22 12:08:10 CDT 2014)
[all classes][org.springframework.batch.repeat.interceptor]

COVERAGE SUMMARY FOR SOURCE FILE [RepeatOperationsInterceptor.java]

nameclass, %method, %block, %line, %
RepeatOperationsInterceptor.java100% (4/4)100% (14/14)100% (194/194)100% (47/47)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class RepeatOperationsInterceptor100% (1/1)100% (5/5)100% (85/85)100% (18/18)
RepeatOperationsInterceptor (): void 100% (1/1)100% (8/8)100% (3/3)
access$100 (RepeatOperationsInterceptor, Object): boolean 100% (1/1)100% (4/4)100% (1/1)
invoke (MethodInvocation): Object 100% (1/1)100% (53/53)100% (11/11)
isComplete (Object): boolean 100% (1/1)100% (13/13)100% (1/1)
setRepeatOperations (RepeatOperations): void 100% (1/1)100% (7/7)100% (3/3)
     
class RepeatOperationsInterceptor$1100% (1/1)100% (2/2)100% (71/71)100% (17/17)
RepeatOperationsInterceptor$1 (RepeatOperationsInterceptor, MethodInvocation,... 100% (1/1)100% (15/15)100% (1/1)
doInIteration (RepeatContext): RepeatStatus 100% (1/1)100% (56/56)100% (16/16)
     
class RepeatOperationsInterceptor$RepeatOperationsInterceptorException100% (1/1)100% (1/1)100% (5/5)100% (2/2)
RepeatOperationsInterceptor$RepeatOperationsInterceptorException (String, Thr... 100% (1/1)100% (5/5)100% (2/2)
     
class RepeatOperationsInterceptor$ResultHolder100% (1/1)100% (6/6)100% (33/33)100% (12/12)
RepeatOperationsInterceptor$ResultHolder (): void 100% (1/1)100% (9/9)100% (3/3)
RepeatOperationsInterceptor$ResultHolder (RepeatOperationsInterceptor$1): void 100% (1/1)100% (3/3)100% (1/1)
getValue (): Object 100% (1/1)100% (3/3)100% (1/1)
isReady (): boolean 100% (1/1)100% (3/3)100% (1/1)
setFinalValue (Object): void 100% (1/1)100% (8/8)100% (4/4)
setValue (Object): void 100% (1/1)100% (7/7)100% (3/3)

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 
17package org.springframework.batch.repeat.interceptor;
18 
19import org.aopalliance.intercept.MethodInterceptor;
20import org.aopalliance.intercept.MethodInvocation;
21import org.springframework.aop.ProxyMethodInvocation;
22import org.springframework.batch.repeat.RepeatStatus;
23import org.springframework.batch.repeat.RepeatCallback;
24import org.springframework.batch.repeat.RepeatContext;
25import org.springframework.batch.repeat.RepeatException;
26import org.springframework.batch.repeat.RepeatOperations;
27import org.springframework.batch.repeat.support.RepeatTemplate;
28import org.springframework.util.Assert;
29 
30/**
31 * A {@link MethodInterceptor} that can be used to automatically repeat calls to
32 * a method on a service. The injected {@link RepeatOperations} is used to
33 * control the completion of the loop. Independent of the completion policy in
34 * the {@link RepeatOperations} the loop will repeat until the target method
35 * returns null or false. Be careful when injecting a bespoke
36 * {@link RepeatOperations} that the loop will actually terminate, because the
37 * default policy for a vanilla {@link RepeatTemplate} will never complete if
38 * the return type of the target method is void (the value returned is always
39 * not-null, representing the {@link Void#TYPE}).
40 * 
41 * @author Dave Syer
42 */
43public class RepeatOperationsInterceptor implements MethodInterceptor {
44 
45        private RepeatOperations repeatOperations = new RepeatTemplate();
46 
47        /**
48         * Setter for the {@link RepeatOperations}.
49         * 
50         * @param batchTempate
51         * @throws IllegalArgumentException if the argument is null.
52         */
53        public void setRepeatOperations(RepeatOperations batchTempate) {
54                Assert.notNull(batchTempate, "'repeatOperations' cannot be null.");
55                this.repeatOperations = batchTempate;
56        }
57 
58        /**
59         * Invoke the proceeding method call repeatedly, according to the properties
60         * of the injected {@link RepeatOperations}.
61         * 
62         * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
63         */
64    @Override
65        public Object invoke(final MethodInvocation invocation) throws Throwable {
66 
67                final ResultHolder result = new ResultHolder();
68                // Cache void return value if intercepted method returns void
69                final boolean voidReturnType = Void.TYPE.equals(invocation.getMethod().getReturnType());
70                if (voidReturnType) {
71                        // This will be ignored anyway, but we want it to be non-null for
72                        // convenience of checking that there is a result.
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                                                        // Save the last result
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                        // The repeat exception should be unwrapped by the template
120                        throw t;
121                }
122 
123                if (result.isReady()) {
124                        return result.getValue();
125                }
126 
127                // No result means something weird happened
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         * @param result
134         * @return
135         */
136        private boolean isComplete(Object result) {
137                return result == null || (result instanceof Boolean) && !((Boolean) result).booleanValue();
138        }
139 
140        /**
141         * Simple wrapper exception class to enable nasty errors to be passed out of
142         * the scope of the repeat operations and handled by the caller.
143         * 
144         * @author Dave Syer
145         * 
146         */
147        private static class RepeatOperationsInterceptorException extends RepeatException {
148                /**
149                 * @param message
150                 * @param e
151                 */
152                public RepeatOperationsInterceptorException(String message, Throwable e) {
153                        super(message, e);
154                }
155        }
156 
157        /**
158         * Simple wrapper object for the result from a method invocation.
159         * 
160         * @author Dave Syer
161         * 
162         */
163        private static class ResultHolder {
164                private Object value = null;
165 
166                private boolean ready = false;
167 
168                /**
169                 * Public setter for the Object.
170                 * @param value the value to set
171                 */
172                public void setValue(Object value) {
173                        this.ready = true;
174                        this.value = value;
175                }
176 
177                /**
178                 * @param value
179                 */
180                public void setFinalValue(Object value) {
181                        if (ready) {
182                                // Only set the value the last time if the last time was also
183                                // the first time
184                                return;
185                        }
186                        setValue(value);
187                }
188 
189                /**
190                 * Public getter for the Object.
191                 * @return the value
192                 */
193                public Object getValue() {
194                        return value;
195                }
196 
197                /**
198                 * @return true if a value has been set
199                 */
200                public boolean isReady() {
201                        return ready;
202                }
203        }
204 
205}

[all classes][org.springframework.batch.repeat.interceptor]
EMMA 2.0.5312 (C) Vladimir Roubtsov