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
018package org.apache.commons.io.file;
019
020import java.math.BigInteger;
021import java.util.Objects;
022
023/**
024 * Provides counters for files, directories, and sizes, as a visit proceeds.
025 *
026 * @since 2.7
027 */
028public class Counters {
029
030    /**
031     * Counts files, directories, and sizes, as a visit proceeds.
032     */
033    private static class AbstractPathCounters implements PathCounters {
034
035        private final Counter byteCounter;
036        private final Counter directoryCounter;
037        private final Counter fileCounter;
038
039        /**
040         * Constructs a new instance.
041         *
042         * @param byteCounter the byte counter.
043         * @param directoryCounter the directory counter.
044         * @param fileCounter the file counter.
045         */
046        protected AbstractPathCounters(final Counter byteCounter, final Counter directoryCounter,
047                final Counter fileCounter) {
048            super();
049            this.byteCounter = byteCounter;
050            this.directoryCounter = directoryCounter;
051            this.fileCounter = fileCounter;
052        }
053
054        @Override
055        public boolean equals(Object obj) {
056            if (this == obj) {
057                return true;
058            }
059            if (!(obj instanceof AbstractPathCounters)) {
060                return false;
061            }
062            AbstractPathCounters other = (AbstractPathCounters) obj;
063            return Objects.equals(byteCounter, other.byteCounter)
064                    && Objects.equals(directoryCounter, other.directoryCounter)
065                    && Objects.equals(fileCounter, other.fileCounter);
066        }
067
068        @Override
069        public Counter getByteCounter() {
070            return byteCounter;
071        }
072
073        @Override
074        public Counter getDirectoryCounter() {
075            return directoryCounter;
076        }
077
078        /**
079         * Gets the count of visited files.
080         *
081         * @return the byte count of visited files.
082         */
083        @Override
084        public Counter getFileCounter() {
085            return this.fileCounter;
086        }
087
088        @Override
089        public int hashCode() {
090            return Objects.hash(byteCounter, directoryCounter, fileCounter);
091        }
092
093        @Override
094        public String toString() {
095            return String.format("%,d files, %,d directories, %,d bytes", Long.valueOf(fileCounter.get()),
096                    Long.valueOf(directoryCounter.get()), Long.valueOf(byteCounter.get()));
097        }
098
099    }
100
101    /**
102     * Counts using a BigInteger number.
103     */
104    private static class BigIntegerCounter implements Counter {
105
106        private BigInteger value = BigInteger.ZERO;
107
108        @Override
109        public void add(final long val) {
110            value = value.add(BigInteger.valueOf(val));
111
112        }
113
114        @Override
115        public boolean equals(Object obj) {
116            if (this == obj) {
117                return true;
118            }
119            if (!(obj instanceof Counter)) {
120                return false;
121            }
122            Counter other = (Counter) obj;
123            return Objects.equals(value, other.getBigInteger());
124        }
125
126        @Override
127        public long get() {
128            return value.longValueExact();
129        }
130
131        @Override
132        public BigInteger getBigInteger() {
133            return value;
134        }
135
136        @Override
137        public Long getLong() {
138            return Long.valueOf(value.longValueExact());
139        }
140
141        @Override
142        public int hashCode() {
143            return Objects.hash(value);
144        }
145
146        @Override
147        public void increment() {
148            value = value.add(BigInteger.ONE);
149        }
150
151        @Override
152        public String toString() {
153            return value.toString();
154        }
155    }
156
157    /**
158     * Counts files, directories, and sizes, as a visit proceeds, using BigInteger numbers.
159     */
160    private static class BigIntegerPathCounters extends AbstractPathCounters {
161
162        /**
163         * Constructs a new initialized instance.
164         */
165        protected BigIntegerPathCounters() {
166            super(Counters.bigIntegerCounter(), Counters.bigIntegerCounter(), Counters.bigIntegerCounter());
167        }
168
169    }
170
171    /**
172     * Counts using a number.
173     */
174    public interface Counter {
175
176        /**
177         * Adds the given number to this counter.
178         *
179         * @param val the value to add.
180         */
181        void add(long val);
182
183        /**
184         * Gets the counter as a long.
185         *
186         * @return the counter as a long.
187         */
188        long get();
189
190        /**
191         * Gets the counter as a BigInteger.
192         *
193         * @return the counter as a BigInteger.
194         */
195        BigInteger getBigInteger();
196
197        /**
198         * Gets the counter as a Long.
199         *
200         * @return the counter as a Long.
201         */
202        Long getLong();
203
204        /**
205         * Adds one to this counter.
206         */
207        void increment();
208
209    }
210
211    /**
212     * Counts using a long number.
213     */
214    private static class LongCounter implements Counter {
215
216        private long value;
217
218        @Override
219        public void add(final long add) {
220            value += add;
221
222        }
223
224        @Override
225        public boolean equals(Object obj) {
226            if (this == obj) {
227                return true;
228            }
229            if (!(obj instanceof Counter)) {
230                return false;
231            }
232            Counter other = (Counter) obj;
233            return value == other.get();
234        }
235
236        @Override
237        public long get() {
238            return value;
239        }
240
241        @Override
242        public BigInteger getBigInteger() {
243            return BigInteger.valueOf(value);
244        }
245
246        @Override
247        public Long getLong() {
248            return Long.valueOf(value);
249        }
250
251        @Override
252        public int hashCode() {
253            return Objects.hash(value);
254        }
255
256        @Override
257        public void increment() {
258            value++;
259        }
260
261        @Override
262        public String toString() {
263            return Long.toString(value);
264        }
265    }
266
267    /**
268     * Counts files, directories, and sizes, as a visit proceeds, using long numbers.
269     */
270    private static class LongPathCounters extends AbstractPathCounters {
271
272        /**
273         * Constructs a new initialized instance.
274         */
275        protected LongPathCounters() {
276            super(Counters.longCounter(), Counters.longCounter(), Counters.longCounter());
277        }
278
279    }
280
281    /**
282     * Counts files, directories, and sizes, as a visit proceeds.
283     */
284    public interface PathCounters {
285
286        /**
287         * Gets the byte counter.
288         *
289         * @return the byte counter.
290         */
291        Counter getByteCounter();
292
293        /**
294         * Gets the directory counter.
295         *
296         * @return the directory counter.
297         */
298        Counter getDirectoryCounter();
299
300        /**
301         * Gets the file counter.
302         *
303         * @return the file counter.
304         */
305        Counter getFileCounter();
306
307    }
308
309    /**
310     * Returns a new BigInteger Counter.
311     *
312     * @return a new BigInteger Counter.
313     */
314    public static Counter bigIntegerCounter() {
315        return new BigIntegerCounter();
316    }
317
318    /**
319     * Returns a new BigInteger PathCounters.
320     *
321     * @return a new BigInteger PathCounters.
322     */
323    public static PathCounters bigIntegerPathCounters() {
324        return new BigIntegerPathCounters();
325    }
326
327    /**
328     * Returns a new long Counter.
329     *
330     * @return a new long Counter.
331     */
332    public static Counter longCounter() {
333        return new LongCounter();
334    }
335
336    /**
337     * Returns a new BigInteger PathCounters.
338     *
339     * @return a new BigInteger PathCounters.
340     */
341    public static PathCounters longPathCounters() {
342        return new LongPathCounters();
343    }
344}