CloseableStopwatch.java

// Generated by delombok at Mon Nov 18 07:27:48 UTC 2024
package de.larssh.utils.time;

import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import de.larssh.utils.CompletedException;

/**
 * Abstract and synchronized implementation of a closeable {@link Stopwatch}.
 * Once a {@code CloseableStopwatch} is closed no more checkpoints can be
 * created and {@link #sinceStart()} and {@link #sinceLast()} return durations
 * based on the stopwatches stopping time.
 *
 * <p>
 * Extending class are meant to be used inside try-with-resource blocks.
 *
 * <p>
 * {@link #close()} can be called multiple times while all but the first call
 * are ignored.
 */
public abstract class CloseableStopwatch extends Stopwatch implements AutoCloseable {
	/**
	 * Instant at the stopwatches stopping or empty if the stopwatch is not stopped,
	 * yet.
	 */
	private volatile Optional<Instant> stopInstant = Optional.empty();
	/**
	 * Object used for locking
	 */
	private final Object lock = new Object();

	/**
	 * Abstract and synchronized implementation of a closeable {@link Stopwatch}.
	 * Once a {@code CloseableStopwatch} is closed no more checkpoints can be
	 * created and {@link #sinceStart()} and {@link #sinceLast()} return durations
	 * based on the stopwatches stopping time.
	 *
	 * <p>
	 * Extending class are meant to be used inside try-with-resource blocks.
	 *
	 * <p>
	 * {@link #close()} can be called multiple times while all but the first call
	 * are ignored.
	 */
	public CloseableStopwatch() {
		// no fields to be initialized
	}

	/**
	 * {@inheritDoc}
	 *
	 * @throws CompletedException Once the {@link CloseableStopwatch} is closed no
	 *                            more checkpoints can be added.
	 */
	@Override
	public Checkpoint checkpoint(final String name) {
		synchronized (lock) {
			if (isStopped()) {
				throw new CompletedException();
			}
			return super.checkpoint(name);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void close() {
		synchronized (lock) {
			if (!isStopped()) {
				stopInstant = Optional.of(Instant.now());
			}
		}
	}

	/**
	 * Returns {@code true} if the stopwatch is stopped.
	 *
	 * @return {@code true} if the stopwatch is stopped
	 */
	public boolean isStopped() {
		return stopInstant.isPresent();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Duration sinceLast() {
		return Duration.between(getLastInstant(), getStopInstant().orElseGet(Instant::now));
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Duration sinceStart() {
		return Duration.between(getStartInstant(), getStopInstant().orElseGet(Instant::now));
	}

	/**
	 * Instant at the stopwatches stopping or empty if the stopwatch is not stopped,
	 * yet.
	 *
	 * @return the instant at the stopwatches stopping or empty
	 */
	@java.lang.SuppressWarnings("all")
	@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
	@lombok.Generated
	public Optional<Instant> getStopInstant() {
		return this.stopInstant;
	}

	@edu.umd.cs.findbugs.annotations.NonNull
	@java.lang.Override
	@java.lang.SuppressWarnings("all")
	@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(justification = "generated code")
	@lombok.Generated
	public java.lang.String toString() {
		return "CloseableStopwatch(super=" + super.toString() + ", stopInstant=" + this.getStopInstant() + ")";
	}
}