001package components.stopwatch;
002
003import java.lang.management.ManagementFactory;
004import java.lang.management.ThreadMXBean;
005
006/**
007 * {@code Stopwatch} represented with two integers and a boolean, with
008 * implementations of all methods.
009 */
010public class Stopwatch1 implements Stopwatch {
011
012    /*
013     * Private members --------------------------------------------------------
014     */
015
016    /**
017     * The last recorded total time (in nanoseconds).
018     */
019    private long previousTotal;
020
021    /**
022     * The start time (in nanoseconds).
023     */
024    private long startTime;
025
026    /**
027     * Records whether {@code this} is running.
028     */
029    private boolean isRunning;
030
031    /**
032     * The managed bean for the thread system of the Java virtual machine.
033     */
034    private static final ThreadMXBean BEAN = ManagementFactory.getThreadMXBean();
035
036    /**
037     * Creator of initial representation.
038     */
039    private void createNewRep() {
040        this.previousTotal = 0;
041        this.startTime = 0;
042        this.isRunning = false;
043    }
044
045    /*
046     * Constructors -----------------------------------------------------------
047     */
048
049    /**
050     * No-argument constructor.
051     */
052    public Stopwatch1() {
053        assert BEAN.isCurrentThreadCpuTimeSupported() : "Violation of: feature supported";
054        this.createNewRep();
055    }
056
057    /*
058     * Standard methods -------------------------------------------------------
059     */
060
061    @Override
062    public final Stopwatch newInstance() {
063        try {
064            return this.getClass().getConstructor().newInstance();
065        } catch (ReflectiveOperationException e) {
066            throw new AssertionError(
067                    "Cannot construct object of type " + this.getClass());
068        }
069    }
070
071    @Override
072    public final void clear() {
073        this.createNewRep();
074    }
075
076    @Override
077    public final void transferFrom(Stopwatch source) {
078        assert source != null : "Violation of: source is not null";
079        assert source != this : "Violation of: source is not this";
080        assert source instanceof Stopwatch1
081                : "Violation of: source is of dynamic type Stopwatch1";
082        /*
083         * This cast cannot fail since the assert above would have stopped
084         * execution in that case.
085         */
086        Stopwatch1 localSource = (Stopwatch1) source;
087        this.previousTotal = localSource.previousTotal;
088        this.startTime = localSource.startTime;
089        this.isRunning = localSource.isRunning;
090        localSource.createNewRep();
091    }
092
093    /*
094     * Kernel methods ---------------------------------------------------------
095     */
096
097    @Override
098    public final void start() {
099        assert !this.isRunning : "Violation of: not this.running";
100        this.isRunning = true;
101        this.startTime = BEAN.getCurrentThreadCpuTime();
102    }
103
104    @Override
105    public final void stop() {
106        assert this.isRunning : "Violation of: this.running";
107        this.previousTotal += BEAN.getCurrentThreadCpuTime() - this.startTime;
108        this.isRunning = false;
109    }
110
111    @Override
112    public final int elapsed() {
113        final long nSec2mSec = 1000000L;
114        if (this.isRunning) {
115            return (int) ((this.previousTotal - this.startTime
116                    + BEAN.getCurrentThreadCpuTime()) / nSec2mSec);
117        } else {
118            return (int) (this.previousTotal / nSec2mSec);
119        }
120    }
121
122    @Override
123    public final boolean isRunning() {
124        return this.isRunning;
125    }
126
127    @Override
128    public final boolean equals(Object obj) {
129        if (obj == this) {
130            return true;
131        }
132        if (obj == null) {
133            return false;
134        }
135        if (!(obj instanceof Stopwatch)) {
136            return false;
137        }
138        Stopwatch s = (Stopwatch) obj;
139        if (this.isRunning() || s.isRunning()) {
140            return false;
141        }
142        if (this.elapsed() != s.elapsed()) {
143            return false;
144        }
145        return true;
146    }
147
148    @Override
149    public final int hashCode() {
150        return this.elapsed();
151    }
152
153    @Override
154    public final String toString() {
155        StringBuilder str = new StringBuilder(
156                "(" + this.elapsed() + "," + this.isRunning() + ")");
157        return str.toString();
158    }
159
160}