EMMA Coverage Report (generated Fri Jan 30 13:20:29 EST 2009)
[all classes][org.springframework.batch.retry.policy]

COVERAGE SUMMARY FOR SOURCE FILE [RecoveryCallbackRetryPolicy.java]

nameclass, %method, %block, %line, %
RecoveryCallbackRetryPolicy.java100% (2/2)94%  (17/18)91%  (204/224)94%  (47.9/51)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class RecoveryCallbackRetryPolicy$RecoveryCallbackRetryContext100% (1/1)89%  (8/9)87%  (126/145)91%  (29/32)
shouldRethrow (RetryContext): boolean 0%   (0/1)0%   (0/5)0%   (0/1)
open (RetryCallback, RetryContext): RetryContext 100% (1/1)69%  (31/45)75%  (6/8)
RecoveryCallbackRetryPolicy$RecoveryCallbackRetryContext (RecoveryCallbackRet... 100% (1/1)100% (24/24)100% (7/7)
canRetry (RetryContext): boolean 100% (1/1)100% (7/7)100% (1/1)
close (RetryContext): void 100% (1/1)100% (7/7)100% (2/2)
getLastThrowable (): Throwable 100% (1/1)100% (4/4)100% (1/1)
getRetryCount (): int 100% (1/1)100% (4/4)100% (1/1)
handleRetryExhausted (RetryContext): Object 100% (1/1)100% (22/22)100% (6/6)
registerThrowable (RetryContext, Throwable): void 100% (1/1)100% (27/27)100% (5/5)
     
class RecoveryCallbackRetryPolicy100% (1/1)100% (9/9)99%  (78/79)100% (18.9/19)
<static initializer> 100% (1/1)94%  (17/18)94%  (0.9/1)
RecoveryCallbackRetryPolicy (): void 100% (1/1)100% (6/6)100% (2/2)
RecoveryCallbackRetryPolicy (RetryPolicy): void 100% (1/1)100% (11/11)100% (4/4)
canRetry (RetryContext): boolean 100% (1/1)100% (5/5)100% (1/1)
close (RetryContext): void 100% (1/1)100% (5/5)100% (2/2)
handleRetryExhausted (RetryContext): Object 100% (1/1)100% (5/5)100% (1/1)
open (RetryCallback, RetryContext): RetryContext 100% (1/1)100% (19/19)100% (4/4)
registerThrowable (RetryContext, Throwable): void 100% (1/1)100% (6/6)100% (2/2)
setDelegate (RetryPolicy): void 100% (1/1)100% (4/4)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 */
16 
17package org.springframework.batch.retry.policy;
18 
19import org.apache.commons.logging.Log;
20import org.apache.commons.logging.LogFactory;
21import org.springframework.batch.repeat.support.RepeatSynchronizationManager;
22import org.springframework.batch.retry.ExhaustedRetryException;
23import org.springframework.batch.retry.RecoveryCallback;
24import org.springframework.batch.retry.RetryCallback;
25import org.springframework.batch.retry.RetryContext;
26import org.springframework.batch.retry.RetryException;
27import org.springframework.batch.retry.RetryPolicy;
28import org.springframework.batch.retry.TerminatedRetryException;
29import org.springframework.batch.retry.callback.RecoveryRetryCallback;
30import org.springframework.batch.retry.context.RetryContextSupport;
31import org.springframework.util.Assert;
32 
33/**
34 * A {@link RetryPolicy} that detects an {@link RecoveryRetryCallback} when it
35 * opens a new context, and uses it to make sure the item is in place for later
36 * decisions about how to retry or backoff. The callback should be an instance
37 * of {@link RecoveryRetryCallback} otherwise an exception will be thrown when
38 * the context is created.
39 * 
40 * @author Dave Syer
41 * 
42 */
43public class RecoveryCallbackRetryPolicy extends AbstractStatefulRetryPolicy {
44 
45        protected Log logger = LogFactory.getLog(getClass());
46 
47        public static final String EXHAUSTED = RecoveryCallbackRetryPolicy.class.getName() + ".EXHAUSTED";
48 
49        private RetryPolicy delegate;
50 
51        /**
52         * Convenience constructor to set delegate on init.
53         * 
54         * @param delegate
55         */
56        public RecoveryCallbackRetryPolicy(RetryPolicy delegate) {
57                super();
58                this.delegate = delegate;
59        }
60 
61        /**
62         * Default constructor. Creates a new {@link SimpleRetryPolicy} for the
63         * delegate.
64         */
65        public RecoveryCallbackRetryPolicy() {
66                this(new SimpleRetryPolicy());
67        }
68 
69        /**
70         * Setter for delegate.
71         * 
72         * @param delegate
73         */
74        public void setDelegate(RetryPolicy delegate) {
75                this.delegate = delegate;
76        }
77 
78        /**
79         * Check the history of this item, and if it has reached the retry limit,
80         * then return false.
81         * 
82         * @see org.springframework.batch.retry.RetryPolicy#canRetry(org.springframework.batch.retry.RetryContext)
83         */
84        public boolean canRetry(RetryContext context) {
85                return ((RetryPolicy) context).canRetry(context);
86        }
87 
88        /**
89         * Delegates to the delegate context.
90         * 
91         * @see org.springframework.batch.retry.RetryPolicy#close(org.springframework.batch.retry.RetryContext)
92         */
93        public void close(RetryContext context) {
94                ((RetryPolicy) context).close(context);
95        }
96 
97        /**
98         * Create a new context for the execution of the callback, which must be an
99         * instance of {@link RecoveryRetryCallback}.
100         * 
101         * @see org.springframework.batch.retry.RetryPolicy#open(org.springframework.batch.retry.RetryCallback,
102         * RetryContext)
103         * 
104         * @throws IllegalStateException if the callback is not of the required
105         * type.
106         */
107        public RetryContext open(RetryCallback callback, RetryContext parent) {
108                Assert.state(callback instanceof RecoveryRetryCallback, "Callback must be RecoveryRetryCallback");
109                RecoveryCallbackRetryContext context = new RecoveryCallbackRetryContext((RecoveryRetryCallback) callback, parent);
110                context.open(callback, null);
111                return context;
112        }
113 
114        /**
115         * If {@link #canRetry(RetryContext)} is false then take remedial action (if
116         * implemented by subclasses), and remove the current item from the history.
117         * 
118         * @see org.springframework.batch.retry.RetryPolicy#registerThrowable(org.springframework.batch.retry.RetryContext,
119         * java.lang.Throwable)
120         */
121        public void registerThrowable(RetryContext context, Throwable throwable) throws TerminatedRetryException {
122                ((RetryPolicy) context).registerThrowable(context, throwable);
123                // The throwable is stored in the delegate context.
124        }
125 
126        /**
127         * Call recovery path (if any) and clean up context history.
128         * 
129         * @see org.springframework.batch.retry.policy.AbstractStatefulRetryPolicy#handleRetryExhausted(org.springframework.batch.retry.RetryContext)
130         */
131        public Object handleRetryExhausted(RetryContext context) throws ExhaustedRetryException {
132                return ((RetryPolicy) context).handleRetryExhausted(context);
133        }
134 
135        private class RecoveryCallbackRetryContext extends RetryContextSupport implements RetryPolicy {
136 
137                final private Object key;
138 
139                final private int initialHashCode;
140 
141                // The delegate context...
142                private RetryContext delegateContext;
143 
144                final private RecoveryCallback recoverer;
145 
146                final private boolean forceRefresh;
147 
148                public RecoveryCallbackRetryContext(RecoveryRetryCallback callback, RetryContext parent) {
149                        super(parent);
150                        this.recoverer = callback.getRecoveryCallback();
151                        this.key = callback.getKey();
152                        this.forceRefresh = callback.isForceRefresh();
153                        this.initialHashCode = key.hashCode();
154                }
155 
156                public boolean canRetry(RetryContext context) {
157                        return delegate.canRetry(this.delegateContext);
158                }
159 
160                public void close(RetryContext context) {
161                        delegate.close(this.delegateContext);
162                }
163 
164                public RetryContext open(RetryCallback callback, RetryContext parent) {
165                        if (forceRefresh) {
166                                // Avoid a cache hit if the caller tells us this is a fresh item
167                                this.delegateContext = delegate.open(callback, null);
168                        }
169                        else if (retryContextCache.containsKey(key)) {
170                                this.delegateContext = retryContextCache.get(key);
171                                if (this.delegateContext == null) {
172                                        throw new RetryException("Inconsistent state for failed item: no history found. "
173                                                        + "Consider whether equals() or hashCode() for the item might be inconsistent, "
174                                                        + "or if you need to supply a better ItemKeyGenerator");
175                                }
176                        }
177                        else {
178                                // Only create a new context if we don't know the history of
179                                // this item:
180                                this.delegateContext = delegate.open(callback, null);
181                        }
182                        // The return value shouldn't be used...
183                        return null;
184                }
185 
186                public void registerThrowable(RetryContext context, Throwable throwable) throws TerminatedRetryException {
187                        // TODO: this comparison assumes that hashCode is the limiting
188                        // factor. Actually the cache should be able to decide for us.
189                        if (this.initialHashCode != key.hashCode()) {
190                                throw new RetryException("Inconsistent state for failed item key: hashCode has changed. "
191                                                + "Consider whether equals() or hashCode() for the item might be inconsistent, "
192                                                + "or if you need to supply a better ItemKeyGenerator");
193                        }
194                        retryContextCache.put(key, this.delegateContext);
195                        delegate.registerThrowable(this.delegateContext, throwable);
196                }
197 
198                public boolean shouldRethrow(RetryContext context) {
199                        // Not called...
200                        throw new UnsupportedOperationException("Not supported - this code should be unreachable.");
201                }
202 
203                public Object handleRetryExhausted(RetryContext context) throws ExhaustedRetryException {
204                        // If there is no going back, then we can remove the history
205                        retryContextCache.remove(key);
206                        RepeatSynchronizationManager.setCompleteOnly();
207                        if (recoverer != null) {
208                                return recoverer.recover(context);
209                        }
210                        logger.info("No recovery callback provided.  Returning null from recovery step.");
211                        // Don't want to call the delegate here - it would throw an exception
212                        return null;
213                }
214 
215                public Throwable getLastThrowable() {
216                        return delegateContext.getLastThrowable();
217                }
218 
219                public int getRetryCount() {
220                        return delegateContext.getRetryCount();
221                }
222 
223        }
224 
225}

[all classes][org.springframework.batch.retry.policy]
EMMA 2.0.5312 (C) Vladimir Roubtsov