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.util.backoff;
018
019import java.util.concurrent.ScheduledExecutorService;
020import java.util.concurrent.TimeUnit;
021import java.util.function.BiConsumer;
022
023import org.apache.camel.util.function.ThrowingFunction;
024
025/**
026 * A simple timer utility that use a linked {@link BackOff} to determine when
027 * a task should be executed.
028 */
029public class BackOffTimer {
030    private final ScheduledExecutorService scheduler;
031
032    public BackOffTimer(ScheduledExecutorService scheduler) {
033        this.scheduler = scheduler;
034    }
035
036    /**
037     * Schedule the given function/task to be executed some time in the future
038     * according to the given backOff.
039     */
040    public Task schedule(BackOff backOff, ThrowingFunction<Task, Boolean, Exception> function) {
041        final BackOffTimerTask task = new BackOffTimerTask(backOff, scheduler, function);
042
043        long delay = task.next();
044        if (delay != BackOff.NEVER) {
045            scheduler.schedule(task, delay, TimeUnit.MILLISECONDS);
046        } else {
047            task.cancel();
048        }
049
050        return task;
051    }
052
053    // ****************************************
054    // TimerTask
055    // ****************************************
056
057    public interface Task {
058        enum Status {
059            Active,
060            Inactive,
061            Exhausted
062        }
063
064        /**
065         * The back-off associated with this task.
066         */
067        BackOff getBackOff();
068
069        /**
070         * Gets the task status.
071         */
072        Status getStatus();
073
074        /**
075         * The number of attempts so far.
076         */
077        long getCurrentAttempts();
078
079        /**
080         * The current computed delay.
081         */
082        long getCurrentDelay();
083
084        /**
085         * The current elapsed time.
086         */
087        long getCurrentElapsedTime();
088
089        /**
090         * The time the last attempt has been performed.
091         */
092        long getLastAttemptTime();
093
094        /**
095         * An indication about the time the next attempt will be made.
096         */
097        long getNextAttemptTime();
098
099        /**
100         * Reset the task.
101         */
102        void reset();
103
104        /**
105         * Cancel the task.
106         */
107        void cancel();
108
109        /**
110         * Action to execute when the context is completed (cancelled or exhausted)
111         *
112         * @param whenCompleted the consumer.
113         */
114        void whenComplete(BiConsumer<Task, Throwable> whenCompleted);
115    }
116}