001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 023 package org.jboss.dna.common.monitor; 024 025 import java.io.Serializable; 026 import java.text.DecimalFormat; 027 import net.jcip.annotations.Immutable; 028 import org.jboss.dna.common.util.StringUtil; 029 030 /** 031 * A snapshot of the progress on an activity. 032 * 033 * @author Randall Hauch 034 */ 035 @Immutable 036 public class ProgressStatus implements Serializable, Comparable<ProgressStatus> { 037 038 /** 039 */ 040 private static final long serialVersionUID = -7771764546193063275L; 041 protected static final String PERCENTAGE_PATTERN = "##0.0"; // percentage should always fit 042 protected static final double PERCENT_PRECISION = 0.001d; 043 044 /** 045 * Compute the percentage worked, accounting for imprecision in 046 * 047 * @param workedSoFar the amount of work so far percentage worked 048 * @param totalWork the total amount of work for this activity 049 * @return the percentage worked 050 */ 051 protected static double computePercentage( double workedSoFar, 052 double totalWork ) { 053 if (isSamePercentage(workedSoFar, 0.0d)) return 0.0d; 054 assert totalWork > 0.0d; 055 double percentage = workedSoFar / totalWork * 100.0d; 056 if (isSamePercentage(percentage, 100.0d)) percentage = 100.0d; 057 return percentage; 058 } 059 060 protected static boolean isSamePercentage( double percentage1, 061 double percentage2 ) { 062 return Math.abs(percentage1 - percentage2) <= PERCENT_PRECISION; 063 } 064 065 private final String activityName; 066 private final double percentWorked; 067 private final boolean done; 068 private final boolean cancelled; 069 private final String message; 070 071 /** 072 * Create the progress status. 073 * 074 * @param activityName the name of the activity, which may not be null 075 * @param message the message for the progress, which may not be null 076 * @param percentWorked the percentage worked, ranging from 0.0 for not started to 100.0 for complete; a negative value are 077 * treated as 0.0, while a value greater than 100.0 is treated as 100.0 078 * @param cancelled true if the activity has been requested to be cancelled, or false otherwise 079 */ 080 public ProgressStatus( String activityName, 081 String message, 082 double percentWorked, 083 boolean cancelled ) { 084 assert activityName != null; 085 assert message != null; 086 this.activityName = activityName; 087 this.done = percentWorked >= 100.0d; 088 this.percentWorked = this.done ? 100.0d : (percentWorked <= 0.0d ? 0.0d : percentWorked); 089 this.message = message; 090 this.cancelled = cancelled; 091 } 092 093 /** 094 * Create the progress status and compute the percentage worked. 095 * 096 * @param activityName the name of the activity, which may not be null 097 * @param message the message for the progress, which may not be null 098 * @param workedSoFar the amount of work so far percentage worked 099 * @param totalWork the total amount of work for this activity 100 * @param cancelled true if the activity has been requested to be cancelled, or false otherwise 101 */ 102 public ProgressStatus( String activityName, 103 String message, 104 double workedSoFar, 105 double totalWork, 106 boolean cancelled ) { 107 this(activityName, message, computePercentage(workedSoFar, totalWork), cancelled); 108 } 109 110 /** 111 * Get the name of the activity. 112 * 113 * @return the activity's name 114 */ 115 public String getActivityName() { 116 return this.activityName; 117 } 118 119 /** 120 * Get the progress as a percentage of the total work that's been completed. 121 * 122 * @return the percentage worked, ranging from 0.0 to 100.0 123 */ 124 public double getPercentWorked() { 125 return this.percentWorked; 126 } 127 128 /** 129 * Get the progress monitor's text message. 130 * 131 * @return the text message 132 */ 133 public String getMessage() { 134 return this.message; 135 } 136 137 /** 138 * Return whether work on this activity has completed. 139 * 140 * @return true if work has completed, or false if work on the activity is still progressing 141 * @see #isCancelled() 142 */ 143 public boolean isDone() { 144 return done; 145 } 146 147 /** 148 * Return whether the activity was requested to be cancelled. 149 * 150 * @return cancelled 151 * @see #isDone() 152 */ 153 public boolean isCancelled() { 154 return this.cancelled; 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public String toString() { 162 String percentage = new DecimalFormat(PERCENTAGE_PATTERN).format(getPercentWorked()); 163 percentage = StringUtil.justifyRight(percentage, PERCENTAGE_PATTERN.length(), ' '); 164 String cancelled = this.isCancelled() ? " (cancelled)" : ""; 165 return this.activityName + " (" + this.message + ") " + percentage + " %" + cancelled; 166 } 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public int hashCode() { 173 return this.getActivityName().hashCode(); 174 } 175 176 /** 177 * {@inheritDoc} 178 */ 179 @Override 180 public boolean equals( Object obj ) { 181 if (this == obj) return true; 182 if (obj instanceof ProgressStatus) { 183 final ProgressStatus that = (ProgressStatus)obj; 184 // First check that the name is the same ... 185 if (!this.getActivityName().equals(that.getActivityName())) return false; 186 // Then check doneness and percent complete ... 187 if (this.isDone() != that.isDone()) return false; 188 if (!isSamePercentage(this.getPercentWorked(), that.getPercentWorked())) return false; 189 return true; 190 } 191 return false; 192 } 193 194 /** 195 * {@inheritDoc} 196 */ 197 public int compareTo( ProgressStatus that ) { 198 if (this == that) return 0; 199 200 // First check the name ... 201 int diff = this.getActivityName().compareTo(that.getActivityName()); 202 if (diff != 0) return diff; 203 204 // Then check the percentage ... 205 return Double.compare(this.getPercentWorked(), that.getPercentWorked()); 206 } 207 }