EMMA Coverage Report (generated Tue May 06 07:29:23 PDT 2008)
[all classes][org.springframework.batch.core.step.item]

COVERAGE SUMMARY FOR SOURCE FILE [StatefulRetryStepFactoryBean.java]

nameclass, %method, %block, %line, %
StatefulRetryStepFactoryBean.java100% (3/3)73%  (8/11)84%  (142/170)79%  (37/47)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class StatefulRetryStepFactoryBean100% (1/1)57%  (4/7)75%  (86/114)68%  (21/31)
setBackOffPolicy (BackOffPolicy): void 0%   (0/1)0%   (0/4)0%   (0/2)
setRetryListeners (RetryListener []): void 0%   (0/1)0%   (0/4)0%   (0/2)
setRetryableExceptionClasses (Class []): void 0%   (0/1)0%   (0/4)0%   (0/2)
applyConfiguration (ItemOrientedStep): void 100% (1/1)82%  (75/91)79%  (15/19)
StatefulRetryStepFactoryBean (): void 100% (1/1)100% (3/3)100% (2/2)
setItemRecoverer (ItemRecoverer): void 100% (1/1)100% (4/4)100% (2/2)
setRetryLimit (int): void 100% (1/1)100% (4/4)100% (2/2)
     
class StatefulRetryStepFactoryBean$StatefulRetryItemHandler100% (1/1)100% (2/2)100% (40/40)100% (11/11)
StatefulRetryStepFactoryBean$StatefulRetryItemHandler (ItemReader, ItemWriter... 100% (1/1)100% (14/14)100% (5/5)
write (Object, StepContribution): void 100% (1/1)100% (26/26)100% (6/6)
     
class StatefulRetryStepFactoryBean$StatefulRetryItemHandler$RetryableItemWriter100% (1/1)100% (2/2)100% (16/16)100% (5/5)
StatefulRetryStepFactoryBean$StatefulRetryItemHandler$RetryableItemWriter (St... 100% (1/1)100% (9/9)100% (3/3)
write (Object): void 100% (1/1)100% (7/7)100% (2/2)

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 */
16package org.springframework.batch.core.step.item;
17 
18import org.springframework.batch.core.Step;
19import org.springframework.batch.core.StepContribution;
20import org.springframework.batch.item.AbstractItemWriter;
21import org.springframework.batch.item.ItemKeyGenerator;
22import org.springframework.batch.item.ItemReader;
23import org.springframework.batch.item.ItemRecoverer;
24import org.springframework.batch.item.ItemWriter;
25import org.springframework.batch.retry.RetryException;
26import org.springframework.batch.retry.RetryListener;
27import org.springframework.batch.retry.RetryOperations;
28import org.springframework.batch.retry.RetryPolicy;
29import org.springframework.batch.retry.backoff.BackOffPolicy;
30import org.springframework.batch.retry.callback.ItemWriterRetryCallback;
31import org.springframework.batch.retry.policy.ItemWriterRetryPolicy;
32import org.springframework.batch.retry.policy.SimpleRetryPolicy;
33import org.springframework.batch.retry.support.RetryTemplate;
34 
35/**
36 * Factory bean for step that executes its item processing with a stateful
37 * retry. Failed items are never skipped, but always cause a rollback. Before a
38 * rollback, the {@link Step} makes a record of the failed item, caching it
39 * under a key given by the {@link ItemKeyGenerator}. Then when it is
40 * re-presented by the {@link ItemReader} it is recognised and retried up to a
41 * limit given by the {@link RetryPolicy}. When the retry is exhausted instead
42 * of the item being skipped it is handled by an {@link ItemRecoverer}.<br/>
43 * 
44 * The skipLimit property is still used to control the overall exception
45 * handling policy. Only exhausted retries count against the exception handler,
46 * instead of counting all exceptions.<br/>
47 * 
48 * This class is not designed for extension. Do not subclass it.
49 * 
50 * @author Dave Syer
51 * 
52 */
53public class StatefulRetryStepFactoryBean extends SkipLimitStepFactoryBean {
54 
55        private ItemRecoverer itemRecoverer;
56 
57        private int retryLimit;
58 
59        private Class[] retryableExceptionClasses;
60 
61        private BackOffPolicy backOffPolicy;
62 
63        private RetryListener[] retryListeners;
64 
65        /**
66         * Public setter for the retry limit. Each item can be retried up to this
67         * limit.
68         * @param retryLimit the retry limit to set
69         */
70        public void setRetryLimit(int retryLimit) {
71                this.retryLimit = retryLimit;
72        }
73 
74        /**
75         * Public setter for the Class[].
76         * @param retryableExceptionClasses the retryableExceptionClasses to set
77         */
78        public void setRetryableExceptionClasses(Class[] retryableExceptionClasses) {
79                this.retryableExceptionClasses = retryableExceptionClasses;
80        }
81 
82        /**
83         * Public setter for the {@link BackOffPolicy}.
84         * @param backOffPolicy the {@link BackOffPolicy} to set
85         */
86        public void setBackOffPolicy(BackOffPolicy backOffPolicy) {
87                this.backOffPolicy = backOffPolicy;
88        }
89 
90        /**
91         * Public setter for the {@link RetryListener}s.
92         * @param retryListeners the {@link RetryListener}s to set
93         */
94        public void setRetryListeners(RetryListener[] retryListeners) {
95                this.retryListeners = retryListeners;
96        }
97 
98        /**
99         * Public setter for the {@link ItemRecoverer}. If this is set the
100         * {@link ItemRecoverer#recover(Object, Throwable)} will be called when
101         * retry is exhausted, and within the business transaction (which will not
102         * roll back because of any other item-related errors).
103         * 
104         * @param itemRecoverer the {@link ItemRecoverer} to set
105         */
106        public void setItemRecoverer(ItemRecoverer itemRecoverer) {
107                this.itemRecoverer = itemRecoverer;
108        }
109 
110        /**
111         * @param step
112         * 
113         */
114        protected void applyConfiguration(ItemOrientedStep step) {
115 
116                super.applyConfiguration(step);
117 
118                if (retryLimit > 0) {
119 
120                        addFatalExceptionIfMissing(RetryException.class);
121 
122                        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(retryLimit);
123                        if (retryableExceptionClasses != null) {
124                                retryPolicy.setRetryableExceptionClasses(retryableExceptionClasses);
125                                retryPolicy.setFatalExceptionClasses(getFatalExceptionClasses());
126                        }
127 
128                        // Co-ordinate the retry policy with the exception handler:
129                        getStepOperations()
130                                        .setExceptionHandler(new SimpleRetryExceptionHandler(retryPolicy, getExceptionHandler(), getFatalExceptionClasses()));
131 
132                        ItemWriterRetryPolicy itemWriterRetryPolicy = new ItemWriterRetryPolicy(retryPolicy);
133 
134                        RetryTemplate retryTemplate = new RetryTemplate();
135                        if (retryListeners != null) {
136                                retryTemplate.setListeners(retryListeners);
137                        }
138                        retryTemplate.setRetryPolicy(itemWriterRetryPolicy);
139                        if (backOffPolicy != null) {
140                                retryTemplate.setBackOffPolicy(backOffPolicy);
141                        }
142 
143                        StatefulRetryItemHandler itemHandler = new StatefulRetryItemHandler(getItemReader(), getItemWriter(),
144                                        retryTemplate, getItemKeyGenerator(), itemRecoverer);
145                        itemHandler.setItemSkipPolicy(getItemSkipPolicy());
146 
147                        step.setItemHandler(itemHandler);
148 
149                }
150 
151        }
152 
153        /**
154         * Extend the skipping handler because we want to take advantage of that
155         * behaviour as well as the retry. So if there is an exception on input it
156         * is skipped if allowed. If there is an exception on output, it will be
157         * re-thrown in any case, and the behaviour when the item is next
158         * encountered depends on the retryable and skippable exception
159         * configuration. Skip takes precedence, so if the exception was skippable
160         * the item will be skipped on input and the reader moves to the next item.
161         * If the exception is retryable but not skippable, then the write will be
162         * attempted up again up to the retry limit. Beyond the retry limit recovery
163         * takes over.
164         * 
165         * @author Dave Syer
166         * 
167         */
168        private static class StatefulRetryItemHandler extends ItemSkipPolicyItemHandler {
169 
170                final private RetryOperations retryOperations;
171 
172                final private ItemKeyGenerator itemKeyGenerator;
173 
174                final private ItemRecoverer itemRecoverer;
175 
176                /**
177                 * @param itemReader
178                 * @param itemWriter
179                 * @param retryTemplate
180                 * @param itemKeyGenerator
181                 * @param itemRecoverer
182                 */
183                public StatefulRetryItemHandler(ItemReader itemReader, ItemWriter itemWriter, RetryOperations retryTemplate,
184                                ItemKeyGenerator itemKeyGenerator, ItemRecoverer itemRecoverer) {
185                        super(itemReader, itemWriter);
186                        this.retryOperations = retryTemplate;
187                        this.itemKeyGenerator = itemKeyGenerator;
188                        this.itemRecoverer = itemRecoverer;
189                }
190 
191                /**
192                 * Execute the business logic, delegating to the writer.<br/>
193                 * 
194                 * Process the item with the {@link ItemWriter} in a stateful retry. The
195                 * {@link ItemRecoverer} is used (if provided) in the case of an
196                 * exception to apply alternate processing to the item. If the stateful
197                 * retry is in place then the recovery will happen in the next
198                 * transaction automatically, otherwise it might be necessary for
199                 * clients to make the recover method transactional with appropriate
200                 * propagation behaviour (probably REQUIRES_NEW because the call will
201                 * happen in the context of a transaction that is about to rollback).<br/>
202                 * 
203                 * @see org.springframework.batch.core.step.item.SimpleItemHandler#write(java.lang.Object,
204                 * org.springframework.batch.core.StepContribution)
205                 */
206                protected void write(Object item, final StepContribution contribution) throws Exception {
207                        ItemWriter writer = new RetryableItemWriter(contribution);
208                        ItemWriterRetryCallback retryCallback = new ItemWriterRetryCallback(item, writer);
209                        retryCallback.setKeyGenerator(itemKeyGenerator);
210                        retryCallback.setRecoverer(itemRecoverer);
211                        retryOperations.execute(retryCallback);
212                }
213 
214                /**
215                 * @author Dave Syer
216                 * 
217                 */
218                private class RetryableItemWriter extends AbstractItemWriter {
219 
220                        private StepContribution contribution;
221 
222                        /**
223                         * @param contribution
224                         */
225                        public RetryableItemWriter(StepContribution contribution) {
226                                this.contribution = contribution;
227                        }
228 
229                        public void write(Object item) throws Exception {
230                                doWriteWithSkip(item, contribution);
231                        }
232 
233                }
234 
235        }
236 
237}

[all classes][org.springframework.batch.core.step.item]
EMMA 2.0.5312 (C) Vladimir Roubtsov