    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     */
    017    package org.apache.commons.math3.util;
    018
    019    import org.apache.commons.math3.exception.MaxCountExceededException;
    020    import org.apache.commons.math3.exception.NullArgumentException;
    021
    022    /**
    023     * Utility that increments a counter until a maximum is reached, at
    024     * which point, the instance will by default throw a
    025     * {@link MaxCountExceededException}.
    026     * However, the user is able to override this behaviour by defining a
    027     * custom {@link MaxCountExceededCallback callback}, in order to e.g.
    028     * select which exception must be thrown.
    029     *
    030     * @since 3.0
    031     * @version $Id: Incrementor.java 1364389 2012-07-22 18:19:26Z tn $
    032     */
    033    public class Incrementor {
    034        /**
    035         * Upper limit for the counter.
    036         */
    037        private int maximalCount;
    038        /**
    039         * Current count.
    040         */
    041        private int count = 0;
    042        /**
    043         * Function called at counter exhaustion.
    044         */
    045        private final MaxCountExceededCallback maxCountCallback;
    046
    047        /**
    048         * Default constructor.
    049         * For the new instance to be useful, the maximal count must be set
    050         * by calling {@link #setMaximalCount(int) setMaximalCount}.
    051         */
    052        public Incrementor() {
    053            this(0);
    054        }
    055
    056        /**
    057         * Defines a maximal count.
    058         *
    059         * @param max Maximal count.
    060         */
    061        public Incrementor(int max) {
    062            this(max,
    063                 new MaxCountExceededCallback() {
    064                     /** {@inheritDoc} */
    065                     public void trigger(int max) {
    066                         throw new MaxCountExceededException(max);
    067                     }
    068                 });
    069        }
    070
    071        /**
    072         * Defines a maximal count and a callback method to be triggered at
    073         * counter exhaustion.
    074         *
    075         * @param max Maximal count.
    076         * @param cb Function to be called when the maximal count has been reached.
    077         * @throws NullArgumentException if {@code cb} is {@code null}
    078         */
    079        public Incrementor(int max,
    080                           MaxCountExceededCallback cb) {
    081            if (cb == null){
    082                throw new NullArgumentException();
    083            }
    084            maximalCount = max;
    085            maxCountCallback = cb;
    086        }
    087
    088        /**
    089         * Sets the upper limit for the counter.
    090         * This does not automatically reset the current count to zero (see
    091         * {@link #resetCount()}).
    092         *
    093         * @param max Upper limit of the counter.
    094         */
    095        public void setMaximalCount(int max) {
    096            maximalCount = max;
    097        }
    098
    099        /**
    100         * Gets the upper limit of the counter.
    101         *
    102         * @return the counter upper limit.
    103         */
    104        public int getMaximalCount() {
    105            return maximalCount;
    106        }
    107
    108        /**
    109         * Gets the current count.
    110         *
    111         * @return the current count.
    112         */
    113        public int getCount() {
    114            return count;
    115        }
    116
    117        /**
    118         * Checks whether a single increment is allowed.
    119         *
    120         * @return {@code false} if the next call to {@link #incrementCount(int)
    121         * incrementCount} will trigger a {@code MaxCountExceededException},
    122         * {@code true} otherwise.
    123         */
    124        public boolean canIncrement() {
    125            return count < maximalCount;
    126        }
    127
    128        /**
    129         * Performs multiple increments.
    130         * See the other {@link #incrementCount() incrementCount} method).
    131         *
    132         * @param value Number of increments.
    133         * @throws MaxCountExceededException at counter exhaustion.
    134         */
    135        public void incrementCount(int value) {
    136            for (int i = 0; i < value; i++) {
    137                incrementCount();
    138            }
    139        }
    140
    141        /**
    142         * Adds one to the current iteration count.
    143         * At counter exhaustion, this method will call the
    144         * {@link MaxCountExceededCallback#trigger(int) trigger} method of the
    145         * callback object passed to the
    146         * {@link #Incrementor(int,MaxCountExceededCallback) constructor}.
    147         * If not explictly set, a default callback is used that will throw
    148         * a {@code MaxCountExceededException}.
    149         *
    150         * @throws MaxCountExceededException at counter exhaustion, unless a
    151         * custom {@link MaxCountExceededCallback callback} has been set at
    152         * construction.
    153         */
    154        public void incrementCount() {
    155            if (++count > maximalCount) {
    156                maxCountCallback.trigger(maximalCount);
    157            }
    158        }
    159
    160        /**
    161         * Resets the counter to 0.
    162         */
    163        public void resetCount() {
    164            count = 0;
    165        }
    166
    167        /**
    168         * Defines a method to be called at counter exhaustion.
    169         * The {@link #trigger(int) trigger} method should usually throw an exception.
    170         */
    171        public interface MaxCountExceededCallback {
    172            /**
    173             * Function called when the maximal count has been reached.
    174             *
    175             * @param maximalCount Maximal count.
    176             */
    177            void trigger(int maximalCount);
    178        }
    179    }