1 /**
2 * Copyright 2005 Steve Molloy
3 *
4 * This file is part of OV4J.
5 *
6 * OV4J is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
8 *
9 * OV4J is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with OV4J; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 */
16 package org.ov4j.retry;
17
18 import java.io.IOException;
19 import java.lang.reflect.InvocationTargetException;
20 import java.util.logging.Level;
21 import java.util.logging.Logger;
22
23 /**
24 * This class performs the retriable calls.
25 *
26 * @author smolloy
27 *
28 */
29 public class RetryCaller implements Runnable {
30 /**
31 * Logger for this class
32 */
33 private static final Logger logger = Logger.getLogger(RetryCaller.class.getName());
34
35 /** Call to be retried. */
36 private RetryableCall theCall;
37
38 /** Result of the call. */
39 private Object theResult;
40
41 /** The RetryHandler. */
42 private final RetryHandler theHandler;
43
44 /**
45 * Constructor.
46 *
47 * @param theCall
48 * The call to retry.
49 * @param theHandler
50 * The RetryHandler.
51 */
52 public RetryCaller(final RetryableCall theCall, final RetryHandler theHandler) {
53 super();
54 this.theCall = theCall;
55 this.theHandler = theHandler;
56 }
57
58 /**
59 * @return Returns the theCall.
60 */
61 public RetryableCall getTheCall() {
62 return theCall;
63 }
64
65 /**
66 * @return Returns the theResult.
67 */
68 public Object getTheResult() {
69 return theResult;
70 }
71
72 /**
73 * Will retry the call the specified number of times and will notify the instance when it reaches the maximum number
74 * of retries or it has a successful result.
75 *
76 * @see java.lang.Runnable#run()
77 */
78 public void run() {
79 if (RetryCaller.logger.isLoggable(Level.FINER)) {
80 RetryCaller.logger.entering("RetryCaller", "run()", "start");
81 }
82
83 Object[] args = null;
84 try {
85 args = theHandler.getArgs(theCall.getArgs());
86 } catch (final IOException e1) {
87 if (RetryCaller.logger.isLoggable(Level.FINE)) {
88 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e1);
89 }
90 }
91 int maxRetryCode = IRetryable.KEEP_TRYING;
92 while (theResult == null && theCall.getNumRetries() <= theHandler.getMaximumRetries()) {
93 try {
94 Thread.sleep(theHandler.getRetryInterval());
95 } catch (final InterruptedException e) {
96 if (RetryCaller.logger.isLoggable(Level.FINE)) {
97 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e);
98 }
99 }
100 try {
101 final IRetryable instance = theHandler.findInstance(theCall.getClassName());
102 if (instance != null) {
103 if (theCall.getNumRetries() >= theHandler.getMaximumRetries()) {
104 final RetryableCallResult result = new RetryableCallResult(theCall, theResult, args);
105 maxRetryCode = instance.maxRetriesReached(result);
106 if (maxRetryCode == IRetryable.KEEP_TRYING) {
107 theCall.setNumRetries(0);
108 } else {
109 theCall.setNumRetries(theCall.getNumRetries() + 1);
110 }
111 } else {
112 theCall.setNumRetries(theCall.getNumRetries() + 1);
113 theResult = theCall.getMethod().invoke(instance, args);
114 final RetryableCallResult result = new RetryableCallResult(theCall, theResult, args);
115 instance.retryCallback(result);
116 }
117 }
118 } catch (final IllegalAccessException e) {
119 if (RetryCaller.logger.isLoggable(Level.FINE)) {
120 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e);
121 }
122 } catch (final IllegalArgumentException e) {
123 if (RetryCaller.logger.isLoggable(Level.FINE)) {
124 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e);
125 }
126 } catch (final InvocationTargetException e) {
127 if (RetryCaller.logger.isLoggable(Level.FINE)) {
128 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e);
129 }
130 }
131 }
132 if (maxRetryCode != IRetryable.TRY_NEXT_RUN) {
133 try {
134 theHandler.callDone(theCall);
135 } catch (final IOException e) {
136 if (RetryCaller.logger.isLoggable(Level.FINE)) {
137 RetryCaller.logger.logp(Level.FINE, "RetryCaller", "run()", "exception ignored", e);
138 }
139 }
140 }
141
142 if (RetryCaller.logger.isLoggable(Level.FINER)) {
143 RetryCaller.logger.exiting("RetryCaller", "run()", "end");
144 }
145 }
146
147 /**
148 * @param theCall
149 * The theCall to set.
150 */
151 public void setTheCall(final RetryableCall theCall) {
152 this.theCall = theCall;
153 }
154
155 /**
156 * @param theResult
157 * The theResult to set.
158 */
159 public void setTheResult(final Object theResult) {
160 this.theResult = theResult;
161 }
162
163 }