001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 package org.apache.fulcrum.yaafi.interceptor.util; 020 021 /** 022 * <p><code>StopWatch</code> provides a convenient API for timings.</p> 023 * 024 * <p>To start the watch, call {@link #start()}. At this point you can:</p> 025 * <ul> 026 * <li>{@link #split()} the watch to get the time whilst the watch continues in the 027 * background. {@link #unsplit()} will remove the effect of the split. At this point, 028 * these three options are available again.</li> 029 * <li>{@link #suspend()} the watch to pause it. {@link #resume()} allows the watch 030 * to continue. Any time between the suspend and resume will not be counted in 031 * the total. At this point, these three options are available again.</li> 032 * <li>{@link #stop()} the watch to complete the timing session.</li> 033 * </ul> 034 * 035 * <p>It is intended that the output methods {@link #toString()} and {@link #getTime()} 036 * should only be called after stop, split or suspend, however a suitable result will 037 * be returned at other points.</p> 038 * 039 * <p>NOTE: As from v2.1, the methods protect against inappropriate calls. 040 * Thus you cannot now call stop before start, resume before suspend or 041 * unsplit before split.</p> 042 * 043 * <p>1. split(), suspend(), or stop() cannot be invoked twice<br /> 044 * 2. unsplit() may only be called if the watch has been split()<br /> 045 * 3. resume() may only be called if the watch has been suspend()<br /> 046 * 4. start() cannot be called twice without calling reset()</p> 047 * 048 * @author Henri Yandell 049 * @author Stephen Colebourne 050 * @since 2.0 051 * @version $Id: StopWatch.java,v 1.1 2005/09/29 13:18:37 sigi Exp $ 052 */ 053 public class StopWatch { 054 055 // running states 056 private static final int STATE_UNSTARTED = 0; 057 private static final int STATE_RUNNING = 1; 058 private static final int STATE_STOPPED = 2; 059 private static final int STATE_SUSPENDED = 3; 060 061 // split state 062 private static final int STATE_UNSPLIT = 10; 063 private static final int STATE_SPLIT = 11; 064 065 /** 066 * The current running state of the StopWatch. 067 */ 068 private int runningState = STATE_UNSTARTED; 069 070 /** 071 * Whether the stopwatch has a split time recorded. 072 */ 073 private int splitState = STATE_UNSPLIT; 074 075 /** 076 * The start time. 077 */ 078 private long startTime = -1; 079 /** 080 * The stop time. 081 */ 082 private long stopTime = -1; 083 084 /** 085 * <p>Constructor.</p> 086 */ 087 public StopWatch() { 088 // nothing to do 089 } 090 091 /** 092 * <p>Start the stopwatch.</p> 093 * 094 * <p>This method starts a new timing session, clearing any previous values.</p> 095 * 096 * @throws IllegalStateException if the StopWatch is already running. 097 */ 098 public void start() 099 { 100 if (this.runningState == STATE_STOPPED) 101 { 102 throw new IllegalStateException( 103 "Stopwatch must be reset before being restarted. " ); 104 } 105 if (this.runningState != STATE_UNSTARTED) 106 { 107 throw new IllegalStateException( "Stopwatch already started. " ); 108 } 109 stopTime = -1; 110 startTime = System.currentTimeMillis(); 111 this.runningState = STATE_RUNNING; 112 } 113 114 /** 115 * <p>Stop the stopwatch.</p> 116 * 117 * <p>This method ends a new timing session, allowing the time to be retrieved.</p> 118 * 119 * @throws IllegalStateException if the StopWatch is not running. 120 */ 121 public void stop() 122 { 123 if (this.runningState != STATE_RUNNING 124 && this.runningState != STATE_SUSPENDED) 125 { 126 throw new IllegalStateException( "Stopwatch is not running. " ); 127 } 128 stopTime = System.currentTimeMillis(); 129 this.runningState = STATE_STOPPED; 130 } 131 132 /** 133 * <p>Resets the stopwatch. Stops it if need be. </p> 134 * 135 * <p>This method clears the internal values to allow the object to be reused.</p> 136 */ 137 public void reset() 138 { 139 this.runningState = STATE_UNSTARTED; 140 this.splitState = STATE_UNSPLIT; 141 startTime = -1; 142 stopTime = -1; 143 } 144 145 /** 146 * <p>Split the time.</p> 147 * 148 * <p>This method sets the stop time of the watch to allow a time to be extracted. 149 * The start time is unaffected, enabling {@link #unsplit()} to continue the 150 * timing from the original start point.</p> 151 * 152 * @throws IllegalStateException if the StopWatch is not running. 153 */ 154 public void split() 155 { 156 if (this.runningState != STATE_RUNNING) 157 { 158 throw new IllegalStateException( "Stopwatch is not running. " ); 159 } 160 stopTime = System.currentTimeMillis(); 161 this.splitState = STATE_SPLIT; 162 } 163 164 /** 165 * <p>Remove a split.</p> 166 * 167 * <p>This method clears the stop time. The start time is unaffected, enabling 168 * timing from the original start point to continue.</p> 169 * 170 * @throws IllegalStateException if the StopWatch has not been split. 171 */ 172 public void unsplit() 173 { 174 if (this.splitState != STATE_SPLIT) 175 { 176 throw new IllegalStateException( "Stopwatch has not been split. " ); 177 } 178 stopTime = -1; 179 this.splitState = STATE_UNSPLIT; 180 } 181 182 /** 183 * <p>Suspend the stopwatch for later resumption.</p> 184 * 185 * <p>This method suspends the watch until it is resumed. The watch will not include 186 * time between the suspend and resume calls in the total time.</p> 187 * 188 * @throws IllegalStateException if the StopWatch is not currently running. 189 */ 190 public void suspend() 191 { 192 if (this.runningState != STATE_RUNNING) 193 { 194 throw new IllegalStateException( 195 "Stopwatch must be running to suspend. " ); 196 } 197 stopTime = System.currentTimeMillis(); 198 this.runningState = STATE_SUSPENDED; 199 } 200 201 /** 202 * <p>Resume the stopwatch after a suspend.</p> 203 * 204 * <p>This method resumes the watch after it was suspended. The watch will not include 205 * time between the suspend and resume calls in the total time.</p> 206 * 207 * @throws IllegalStateException if the StopWatch has not been suspended. 208 */ 209 public void resume() 210 { 211 if (this.runningState != STATE_SUSPENDED) 212 { 213 throw new IllegalStateException( 214 "Stopwatch must be suspended to resume. " ); 215 } 216 startTime += (System.currentTimeMillis() - stopTime); 217 stopTime = -1; 218 this.runningState = STATE_RUNNING; 219 } 220 221 /** 222 * <p>Get the time on the stopwatch.</p> 223 * 224 * <p>This is either the time between the start and the moment this method 225 * is called, or the amount of time between start and stop.</p> 226 * 227 * @return the time in milliseconds 228 */ 229 public long getTime() 230 { 231 if (this.runningState == STATE_STOPPED 232 || this.runningState == STATE_SUSPENDED) 233 { 234 return this.stopTime - this.startTime; 235 } 236 else if (this.runningState == STATE_UNSTARTED) 237 { 238 return 0; 239 } 240 else if (this.runningState == STATE_RUNNING) 241 { 242 return System.currentTimeMillis() - this.startTime; 243 } 244 throw new RuntimeException( "Illegal running state has occured. " ); 245 } 246 247 /** 248 * <p>Get the split time on the stopwatch.</p> 249 * 250 * <p>This is the time between start and latest split. </p> 251 * 252 * @return the split time in milliseconds 253 * 254 * @throws IllegalStateException if the StopWatch has not yet been split. 255 * @since 2.1 256 */ 257 public long getSplitTime() 258 { 259 if (this.splitState != STATE_SPLIT) 260 { 261 throw new IllegalStateException( 262 "Stopwatch must be split to get the split time. " 263 ); 264 } 265 return this.stopTime - this.startTime; 266 } 267 268 /** 269 * <p>Gets a summary of the time that the stopwatch recorded as a string.</p> 270 * 271 * @return the time as a String 272 */ 273 public String toString() { 274 return getTime()+"ms"; 275 } 276 }