package org.apache.lucene.util; /* * Copyright 2006-2007 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Convenient class for reporting progress on a long, possibly complex * multi-phase, process. * * @author Martin Haye */ public abstract class ProgressTracker implements Cloneable { private float loPct; private float hiPct; private int minInterval = 30 * 1000; // 30 seconds private IntHolder prevPctDone = new IntHolder(); private LongHolder prevTime = new LongHolder(); private StringHolder prevDescrip = new StringHolder(); /** Initialize a 0..100% tracker */ public ProgressTracker() { this(0, 100); } /** Initialize a tracker for some other percentage range */ public ProgressTracker(float loPct, float hiPct) { this.loPct = loPct; this.hiPct = hiPct; prevPctDone.value = -1; } /** * Override the default update interval of 30 seconds * * @param millisecs how many milliseconds between updates (minimum) */ public void setMinInterval(int millisecs) { minInterval = millisecs; } /** * Split this tracker into two sub-trackers, based on how much work * each sub-tracker needs to do. */ public ProgressTracker[] split(long work1, long work2) { return split(new long[] { work1, work2 }); } /** * Split this tracker into three sub-trackers, based on how much work * each sub-tracker needs to do. */ public ProgressTracker[] split(long work1, long work2, long work3) { return split(new long[] { work1, work2, work3 }); } /** * Split this tracker into four sub-trackers, based on how much work * each sub-tracker needs to do. */ public ProgressTracker[] split(long work1, long work2, long work3, long work4) { return split(new long[] { work1, work2, work3, work4 }); } /** * Split this tracker into an arbitrary number of sub-trackers, based on * how much work each sub-tracker needs to do. This is useful for multi- * phase processes. */ public ProgressTracker[] split(long[] works) { long total = 0; for (int i = 0; i < works.length; i++) total += works[i]; ProgressTracker[] out = new ProgressTracker[works.length]; long accum = 0; for (int i = 0; i < works.length; i++) { out[i] = (ProgressTracker)clone(); out[i].loPct = loPct + (accum * (hiPct - loPct) / total); accum += works[i]; out[i].hiPct = loPct + (accum * (hiPct - loPct) / total); } return out; } /** Clone this tracker */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } } /** To be called periodically by code that does work. */ public void progress(long workDone, long totalWork, String descrip) { progress(workDone, totalWork, descrip, false); } /** To be called periodically by code that does work. */ public void progress(long workDone, long totalWork, String descrip, boolean force) { // Calculate the percent done int pctDone = (int)(loPct + (workDone * (hiPct - loPct) / totalWork)); // If we no percentage change, skip this unless forced. if (!force && pctDone <= prevPctDone.value) return; // Percent has changed. However, if it's not time to print a message yet, // consider this boring and skip it (unless forced) // if (!force && System.currentTimeMillis() - prevTime.value < minInterval) { return; } // Okay, time to actually report what's going on. report(pctDone, descrip.equals(prevDescrip.value) ? "" : descrip); // Record the current values for comparison next time prevTime.value = System.currentTimeMillis(); prevPctDone.value = pctDone; prevDescrip.value = descrip; } /** Supply this method to actually print out the progress */ public abstract void report(int pctDone, String descrip); // Utility holder classes -- useful to keep one copy of the state data // across all the sub-clones. // private class IntHolder { int value; } private class LongHolder { long value; } private class StringHolder { String value; } }