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