001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.processor.aggregate; 018 019import java.util.Random; 020 021/** 022 * Class to control how failed optimistic locks are tried. This policy supports random and exponential back-off delays. 023 * <p/> 024 * If {@code randomBackOff} is enabled and a value is supplied for {@code retryDelay} the value will be ignored. 025 * <p/> 026 * If {@code randomBackOff} is enabled and no value is set for {@code maximumRetryDelay}, a default value of 1000ms will 027 * be used, the random delay will be between 0 and 1000 milliseconds. 028 * <p/> 029 * If both {@code randomBackOff} and {@code exponentialBackOff} are enabled, {@code exponentialBackOff} will take precedence. 030 * <p/> 031 * If {@code exponentialBackOff} is enabled and a value is set for {@code maximumRetryDelay}, the retry delay will keep 032 * doubling in value until it reaches or exceeds {@code maximumRetryDelay}. After it has reached or exceeded {@code maximumRetryDelay} 033 * the value of {@code maximumRetryDelay} will be used as the retry delay. 034 * <p/> 035 * If both {@code exponentialBackOff} and {@code randomBackOff} are disabled, the value of {@code retryDelay} will be used 036 * as the retry delay and remain constant through all the retry attempts. 037 * <p/> 038 * If the value of {@code maximumRetries} is set above zero, retry attempts will stop at the value specified. 039 * <p/> 040 * The default behaviour of this policy is to retry forever and exponentially increase the back-off delay starting with 50ms. 041 * 042 * @version 043 */ 044public class OptimisticLockRetryPolicy { 045 private static final long DEFAULT_MAXIMUM_RETRY_DELAY = 1000L; 046 047 private int maximumRetries; 048 private long retryDelay = 50L; 049 private long maximumRetryDelay; 050 private boolean exponentialBackOff = true; 051 private boolean randomBackOff; 052 053 public OptimisticLockRetryPolicy() { 054 } 055 056 public boolean shouldRetry(final int retryCounter) { 057 return maximumRetries <= 0 || retryCounter < maximumRetries; 058 } 059 060 public void doDelay(final int retryCounter) throws InterruptedException { 061 if (retryDelay > 0 || randomBackOff) { 062 long sleepFor; 063 sleepFor = exponentialBackOff ? (retryDelay << retryCounter) 064 : (randomBackOff ? new Random().nextInt((int)(maximumRetryDelay > 0 ? maximumRetryDelay : DEFAULT_MAXIMUM_RETRY_DELAY)) : retryDelay); 065 if (maximumRetryDelay > 0 && sleepFor > maximumRetryDelay) { 066 sleepFor = maximumRetryDelay; 067 } 068 Thread.sleep(sleepFor); 069 } 070 } 071 072 public int getMaximumRetries() { 073 return maximumRetries; 074 } 075 076 public void setMaximumRetries(int maximumRetries) { 077 this.maximumRetries = maximumRetries; 078 } 079 080 public OptimisticLockRetryPolicy maximumRetries(int maximumRetries) { 081 setMaximumRetries(maximumRetries); 082 return this; 083 } 084 085 public long getRetryDelay() { 086 return retryDelay; 087 } 088 089 public void setRetryDelay(long retryDelay) { 090 this.retryDelay = retryDelay; 091 } 092 093 public OptimisticLockRetryPolicy retryDelay(long retryDelay) { 094 setRetryDelay(retryDelay); 095 return this; 096 } 097 098 public long getMaximumRetryDelay() { 099 return maximumRetryDelay; 100 } 101 102 public void setMaximumRetryDelay(long maximumRetryDelay) { 103 this.maximumRetryDelay = maximumRetryDelay; 104 } 105 106 public OptimisticLockRetryPolicy maximumRetryDelay(long maximumRetryDelay) { 107 setMaximumRetryDelay(maximumRetryDelay); 108 return this; 109 } 110 111 public boolean isExponentialBackOff() { 112 return exponentialBackOff; 113 } 114 115 public void setExponentialBackOff(boolean exponentialBackOff) { 116 this.exponentialBackOff = exponentialBackOff; 117 } 118 119 public OptimisticLockRetryPolicy exponentialBackOff() { 120 setExponentialBackOff(true); 121 return this; 122 } 123 124 public boolean isRandomBackOff() { 125 return randomBackOff; 126 } 127 128 public void setRandomBackOff(boolean randomBackOff) { 129 this.randomBackOff = randomBackOff; 130 } 131 132 public OptimisticLockRetryPolicy randomBackOff() { 133 setRandomBackOff(true); 134 return this; 135 } 136 137 @Override 138 public String toString() { 139 final StringBuilder sb = new StringBuilder("OptimisticLockRetryPolicy["); 140 sb.append("maximumRetries=").append(maximumRetries); 141 sb.append(", retryDelay=").append(retryDelay); 142 sb.append(", maximumRetryDelay=").append(maximumRetryDelay); 143 sb.append(", exponentialBackOff=").append(exponentialBackOff); 144 sb.append(", randomBackOff=").append(randomBackOff); 145 sb.append(']'); 146 return sb.toString(); 147 } 148}