View Javadoc

1   /**
2    * Copyright 2007 Björn Voß
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * 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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.oxclient.aspects.retry;
17  
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import org.aspectj.lang.ProceedingJoinPoint;
22  import org.aspectj.lang.annotation.Around;
23  import org.aspectj.lang.annotation.Aspect;
24  import org.aspectj.lang.annotation.Pointcut;
25  
26  /**
27   * @author Björn Voß
28   *
29   */
30  @Aspect()
31  public class RetryHandler {
32  
33  	private int retries = 3;
34  	private int delay = 200;
35  
36  	private final Map<ParameterSaveType, IParameterSaver> parameterSaverMap;
37  
38  	/**
39  	 * This Constructor is only for unit testing!<br>
40  	 * It should never be used.
41  	 * <p>The AspectJ compiler will also use the default constructor.
42  	 *
43  	 * @param parameterSaverMap
44  	 */
45  	public RetryHandler(
46  			final Map<ParameterSaveType, IParameterSaver> parameterSaverMap) {
47  		super();
48  		this.parameterSaverMap = parameterSaverMap;
49  	}
50  
51  
52  
53  	public RetryHandler() {
54  		super();
55  		this.parameterSaverMap = new HashMap<ParameterSaveType, IParameterSaver>();
56  		this.parameterSaverMap.put(ParameterSaveType.REFERENCE, new ReferenceSaver());
57  	}
58  
59  
60  
61  	@Pointcut(value="@annotation(retry) " +
62  			  "&& execution(public * *(..))")
63  	public void shouldRetry(@SuppressWarnings("unused")	final RetryIt retry) {
64  		//pointcut
65  	}
66  
67  	@Around("shouldRetry(retry)")
68  	public Object doWithRetry(final ProceedingJoinPoint pjp, final RetryIt retry) throws Throwable {
69  		final ParameterSaveType saveType = retry.saverType();
70  		final IParameterSaver parameterSaver =
71  				this.parameterSaverMap.get(saveType);
72  		final Object[] origArgs = pjp.getArgs();
73  		parameterSaver.saveOriginalParameters(origArgs);
74  
75  		try {
76  			//first time use the original arguments, remember they were
77  			//saved already
78  			return pjp.proceed(origArgs);
79  		} catch (final Throwable th) {
80  			final Class<? extends Throwable>[] retryFor = retry.retryFor();
81  			if (shouldHandel(th, retryFor)) {
82  				return retryProceed(pjp, retry, parameterSaver, retryFor);
83  			}
84  			throw th;
85  		}
86  	}
87  
88  
89  	private Object retryProceed(
90  			final ProceedingJoinPoint pjp,
91  			final RetryIt retry,
92  			final IParameterSaver parameterSaver,
93  			final Class<? extends Throwable>[] retryFor) throws Throwable {
94  		final boolean useglobal = retry.useGlobalSettings();
95  		final int myDelay = this.delay;
96  		final int myRetries = this.retries;
97  		int mytries = 0;
98  		Throwable lasThrowable = null;
99  		do {
100 			//give the world time to get ready for the job ;-)
101 			Thread.sleep(myDelay);
102 			try {
103 				//this time use loaded arguments
104 				return pjp.proceed(parameterSaver.loadOriginalParameters());
105 			} catch (final Throwable th) {
106 				if (shouldHandel(th, retryFor)) {
107 					mytries++;
108 					lasThrowable = th;
109 				} else {
110 					throw th;
111 				}
112 			}
113 		} while (mytries < myRetries);
114 		throw lasThrowable;
115 	}
116 
117 	private boolean shouldHandel(final Throwable th, final Class<? extends Throwable>[] retryFor) {
118 		for (final Class<? extends Throwable> clazz : retryFor) {
119 			if (clazz.isInstance(th)) {
120 				return true;
121 			}
122 		}
123 		return false;
124 	}
125 
126 
127 
128 	public int getRetries() {
129 		return this.retries;
130 	}
131 
132 	public void setRetries(final int retries) {
133 		this.retries = retries;
134 	}
135 
136 	public int getDelay() {
137 		return this.delay;
138 	}
139 
140 	public void setDelay(final int delay) {
141 		this.delay = delay;
142 	}
143 }