1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.util.interceptors;
18
19 import org.aopalliance.intercept.MethodInterceptor;
20 import org.aopalliance.intercept.MethodInvocation;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 /***
25 * Generic aspect that will attempt to replay a method invocation if one of a
26 * set of specified exceptions is thrown from its execution.
27 *
28 * @author a336317
29 */
30 public class MethodReplayInterceptor implements MethodInterceptor
31 {
32
33 /*** Log reference */
34 private Log log = LogFactory.getLog(MethodReplayInterceptor.class);
35
36 /*** Serialization version identifier */
37 private static final long serialVersionUID = -1316279974504594833L;
38
39 /***
40 * How many times we should attempt to retry the method invocation if it
41 * fails
42 */
43 private int retryCount;
44
45 /*** How long we should wait before retrying - specified in milliseconds * */
46 private int retryInterval;
47
48 /***
49 * Object which decides whether or not a method invocation should be
50 * replayed
51 */
52 private TransactionalMethodReplayDecisionMaker replayDecisionMaker;
53
54 /***
55 * Encloses <code>super.invoke()</code> in a try/catch block, where the
56 * catch block contains additional retry logic.
57 */
58 public Object invoke(MethodInvocation invocation) throws Throwable
59 {
60
61 try
62 {
63 return invocation.proceed();
64 } catch (Exception exp)
65 {
66
67
68 if (!this.isReplayable(invocation, exp)) { throw exp; }
69
70
71 if (log.isDebugEnabled())
72 {
73 log
74 .debug("Invocation for method ["
75 + invocation.getMethod().toString()
76 + "] failed. Will attempt to replay method invocation ["
77 + retryCount + "] times with an interval of ["
78 + retryInterval + "] milliseconds");
79 }
80
81 int retryCounter = 1;
82 Exception lastExp = null;
83
84 while ((retryCounter < retryCount))
85 {
86
87 try
88 {
89 if (log.isDebugEnabled())
90 {
91 log
92 .debug("Sleeping for ["
93 + retryInterval
94 + "] milliseconds before replaying invocation for method ["
95 + invocation.getMethod().toString()
96 + "].");
97 }
98 Thread.sleep(this.retryInterval);
99
100 if (log.isDebugEnabled())
101 {
102 log.debug("Attempt invocation [" + retryCounter
103 + "] for method ["
104 + invocation.getMethod().toString() + "].");
105 }
106
107
108 return invocation.proceed();
109 } catch (Exception exp2)
110 {
111
112
113 if (!this.isReplayable(invocation, exp)) { throw exp; }
114
115 if (log.isDebugEnabled())
116 {
117 log.debug("Attempt [" + retryCounter
118 + "] to replay invocation for method ["
119 + invocation.getMethod().toString()
120 + "] failed. [" + (retryCount - retryCounter)
121 + "] attempts left.");
122 }
123
124 lastExp = exp2;
125 retryCounter++;
126 }
127 }
128 if (log.isDebugEnabled())
129 {
130 log.debug("[" + retryCounter
131 + "] attempts to replay invocation for method ["
132 + invocation.getMethod().toString()
133 + "] failed. Throwing exception ["
134 + lastExp.getClass().getName() + "]");
135 }
136 throw lastExp;
137 }
138
139 }
140
141 public int getRetryCount()
142 {
143 return retryCount;
144 }
145
146 public void setRetryCount(int retryCount)
147 {
148 this.retryCount = retryCount;
149 }
150
151 public int getRetryInterval()
152 {
153 return retryInterval;
154 }
155
156 public void setRetryInterval(int retryInterval)
157 {
158 this.retryInterval = retryInterval;
159 }
160
161 /***
162 * Determine if we should attempt to replay the method given that the
163 * previous invocation returned the passed exception.
164 *
165 * @param exp
166 * @return True if we should replay the method.
167 */
168 private boolean isReplayable(MethodInvocation invocation, Exception exp)
169 {
170 return replayDecisionMaker.shouldReplay(invocation, exp);
171 }
172
173 public void setReplayDecisionMaker(
174 TransactionalMethodReplayDecisionMaker replayDecisionMaker)
175 {
176 this.replayDecisionMaker = replayDecisionMaker;
177 }
178
179 }