View Javadoc

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 }