package com.crawljax.core;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Singleton;
import com.crawljax.core.configuration.CrawljaxConfiguration;
import com.google.common.annotations.VisibleForTesting;
@Singleton
@ThreadSafe
public class ExitNotifier {
/**
* Represents the reason Crawljax stopped.
*/
public enum ExitStatus {
/**
* The maximum number of states is reached as defined in
* {@link CrawljaxConfiguration#getMaximumStates()}.
*/
MAX_STATES("Maximum states passed"),
/**
* The maximum crawl time is reached as defined in
* {@link CrawljaxConfiguration#getMaximumRuntime()}.
*/
MAX_TIME("Maximum time passed"),
/**
* The crawl is done.
*/
EXHAUSTED("Exausted"),
/**
* The crawler quite because of an error.
*/
ERROR("Errored"),
/**
* When {@link CrawljaxRunner#stop()} has been called.
*/
STOPPED("Stopped manually");
private final String readableName;
private ExitStatus(String readableName) {
this.readableName = readableName;
}
@Override
public String toString() {
return readableName;
}
}
private final CountDownLatch latch = new CountDownLatch(1);
private final AtomicInteger states = new AtomicInteger();
private final int maxStates;
private ExitStatus reason = ExitStatus.ERROR;
public ExitNotifier(int maxStates) {
this.maxStates = maxStates;
}
/**
* Waits until the crawl has to stop.
*
* @throws InterruptedException
* When the wait is interrupted.
*/
public ExitStatus awaitTermination() throws InterruptedException {
latch.await();
return reason;
}
/**
* @return The new number of states.
*/
public int incrementNumberOfStates() {
int count = states.incrementAndGet();
if (count == maxStates) {
reason = ExitStatus.MAX_STATES;
latch.countDown();
}
return count;
}
public void signalTimeIsUp() {
reason = ExitStatus.MAX_TIME;
latch.countDown();
}
/**
* Signal that all {@link CrawlTaskConsumer}s are done.
*/
public void signalCrawlExhausted() {
reason = ExitStatus.EXHAUSTED;
latch.countDown();
}
/**
* Manually stop the crawl.
*/
public void stop() {
reason = ExitStatus.STOPPED;
latch.countDown();
}
@VisibleForTesting
boolean isExitCalled() {
return latch.getCount() == 0;
}
}