001/** 002 * Copyright 2010-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.common.util.inform; 017 018import org.kuali.common.util.Assert; 019 020/** 021 * Print a dot to the console each time we make at least 1% progress towards a total 022 */ 023public final class PercentCompleteInformer { 024 025 public static final int DEFAULT_PERCENTAGE_INCREMENT = 1; 026 public static final long UNINITIALIZED_PROGRESS_INDICATOR = -1; 027 public static final int UNINITIALIZED_PERCENT_COMPLETE_INDICATOR = -1; 028 029 private final int percentageIncrement; 030 private final long total; 031 private final Inform inform; 032 private final StartStopInformer informer; 033 034 public PercentCompleteInformer(long total) { 035 this(total, DEFAULT_PERCENTAGE_INCREMENT); 036 } 037 038 public PercentCompleteInformer(long total, int percentageIncrement) { 039 this(total, DEFAULT_PERCENTAGE_INCREMENT, Inform.DEFAULT_INFORM); 040 } 041 042 public PercentCompleteInformer(long total, int percentageIncrement, Inform inform) { 043 Assert.isTrue(total >= 0, "total is negative"); 044 Assert.isTrue(percentageIncrement > 0, "percentage increment must be greater than zero"); 045 Assert.noNulls(inform); 046 this.total = total; 047 this.inform = inform; 048 this.percentageIncrement = percentageIncrement; 049 this.informer = new StartStopInformer(inform); 050 } 051 052 private int percentComplete = UNINITIALIZED_PERCENT_COMPLETE_INDICATOR; 053 private volatile long progress = UNINITIALIZED_PROGRESS_INDICATOR; 054 private boolean started = false; 055 056 /** 057 * Indicates if we are in the "started" state or not 058 */ 059 public boolean isStarted() { 060 return started; 061 } 062 063 /** 064 * Indicates how far along we are 065 */ 066 public long getProgress() { 067 return progress; 068 } 069 070 /** 071 * Indicates how far along we are as a percentage 072 */ 073 public int getPercentComplete() { 074 return percentComplete; 075 } 076 077 /** 078 * Thread safe method to indicate progress has begun 079 */ 080 public synchronized void start() { 081 Assert.isFalse(started, "Already started"); 082 this.started = true; 083 this.percentComplete = 0; 084 this.progress = 0; 085 informer.start(); 086 } 087 088 /** 089 * Thread safe method for incrementing progress by one 090 */ 091 public void incrementProgress() { 092 incrementProgress(1); 093 } 094 095 /** 096 * Thread safe method for incrementing progress by <code>amount</code> 097 */ 098 public synchronized void incrementProgress(long amount) { 099 // Make sure were are in the started state 100 Assert.isTrue(started, "Not started"); 101 102 // Increment the progress indicator 103 this.progress += amount; 104 105 // Calculate how far along we are 106 int newPercentCompleted = (int) ((progress * 100) / total); 107 108 // Have we made at least 1% progress? 109 if (isEnoughProgress(newPercentCompleted, percentComplete, percentageIncrement)) { 110 // If so, update the field holding the percent complete 111 this.percentComplete = newPercentCompleted; 112 // and print a dot to the console 113 inform.getPrintStream().print(inform.getProgressToken()); 114 } 115 } 116 117 /** 118 * Thread safe method to indicate progress has stopped 119 */ 120 public synchronized void stop() { 121 Assert.isTrue(started, "Not started"); 122 this.started = false; 123 this.percentComplete = UNINITIALIZED_PERCENT_COMPLETE_INDICATOR; 124 this.progress = UNINITIALIZED_PROGRESS_INDICATOR; 125 informer.stop(); 126 } 127 128 protected boolean isEnoughProgress(int newPercentCompleted, int percentComplete, int percentageIncrement) { 129 int needed = percentComplete + percentageIncrement; 130 return newPercentCompleted >= needed; 131 } 132 133 public int getPercentageIncrement() { 134 return percentageIncrement; 135 } 136 137 public long getTotal() { 138 return total; 139 } 140 141 public Inform getInform() { 142 return inform; 143 } 144 145 public StartStopInformer getInformer() { 146 return informer; 147 } 148 149}