Retenter l'execution d'une fonction plusieurs fois en Java
Par MD3804-GANDI le lundi 23 novembre 2009, 11:19 - Java / J2EE - Lien permanent
Certains d'entre vous connaissent peut être la fonction javascript Try.these de Prototype.
Elle permet d'exécuter plusieurs fonctions et de retourner la valeur de la première fonction qui ne génère pas d'exception. Cela permet d'essayer plusieurs façons de faire, mais aussi de retenter l'exécution d'une fonction, si on lui passe plusieurs fois la même fonction.
Je vous propose un code qui permet de faire l'équivalent en java. Pour cela
J'ai utilisé le patron de conception 'template' et les génériques Java 5. J'ai
eu besoin de coder cela afin d'être plus tolérant aux erreurs (retenter
plusieurs fois une requête HTTP qui pouvait aboutir à un timeout serveur). Je
vous conseille de restreindre le catch de la fonction retry()
afin
de de ne retenter l'exécution, uniquement pour une exception donnée et de
propager les autres exceptions le cas échéant.
Voci le code :
package com.gisgraphy; public abstract class RetryOnErrorTemplate { private int alreadyTry = 0; private int numberOfTimesToRetry = 1; private T returnvalue = null; private RetryOnErrorTemplate retry() throws Exception { try { returnvalue = tryThat(); alreadyTry++; return this; } catch (Exception e) { numberOfTimesToRetry--; alreadyTry++; if (numberOfTimesToRetry == 0) { throw e; } else { return retry(); } } } public abstract T tryThat() throws Exception; public T times(int numberOfTry) throws Exception { this.numberOfTimesToRetry = numberOfTry; retry(); return returnvalue; } /** * @return The number of times the code has already been try */ public int getAlreadyTry() { return alreadyTry; } /** * @return The number of times the code should be try */ public int getNumberOfTimesToRetry() { return numberOfTimesToRetry; } }
Voci le test JUnit 4:
package com.gisgraphy; import junit.framework.Assert; import org.junit.Test; import com.gisgraphy.domain.geoloc.service.geoloc.GisgraphyCommunicationException; public class RetryOnErrorTemplateTest { private static final String THE_RETURNED_VALUE = "The returned value"; @Test public void testRetryWhenCodeThrows() throws Exception { RetryOnErrorTemplate<String> retryOnError = new RetryOnErrorTemplate<String>() { @Override public String tryThat() throws Exception { if (true) { throw new GisgraphyCommunicationException(); } return "will never be return"; } }; try { retryOnError.times(3); Assert.fail("the code should have throws"); } catch (GisgraphyCommunicationException ignore) { } Assert.assertEquals("The number of retry is not the expected one",3, retryOnError.getAlreadyTry()); } @Test public void testRetryWhenCodeDoesnTThrows() throws Exception { RetryOnErrorTemplate<String> retryOnError = new RetryOnErrorTemplate<String>() { @Override public String tryThat() throws Exception { return THE_RETURNED_VALUE; } }; Assert.assertEquals("The returned value is not the expected one",THE_RETURNED_VALUE, retryOnError.times(3)); Assert.assertEquals("Only one try should have been done",1, retryOnError.getAlreadyTry()); } }