io.codearte.accurest.stubrunner.AvailablePortScanner.groovy Maven / Gradle / Ivy
package io.codearte.accurest.stubrunner
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.util.logging.Slf4j
/**
* Tries to execute a closure with an available port from the given range
*/
@CompileStatic
@Slf4j
@PackageScope
class AvailablePortScanner {
private static final int MAX_RETRY_COUNT = 1000
private final int minPortNumber
private final int maxPortNumber
private final int maxRetryCount
AvailablePortScanner(int minPortNumber, int maxPortNumber, int maxRetryCount = MAX_RETRY_COUNT) {
checkPortRanges(minPortNumber, maxPortNumber)
this.minPortNumber = minPortNumber
this.maxPortNumber = maxPortNumber
this.maxRetryCount = maxRetryCount
}
private void checkPortRanges(int minPortNumber, int maxPortNumber) {
if (minPortNumber > maxPortNumber) {
throw new InvalidPortRange(minPortNumber, maxPortNumber)
}
}
public T tryToExecuteWithFreePort(Closure closure) {
for (i in (1..maxRetryCount)) {
try {
int numberOfPortsToBind = maxPortNumber - minPortNumber + 1
int portToScan = new Random().nextInt(numberOfPortsToBind) + minPortNumber
checkIfPortIsAvailable(portToScan)
return executeLogicForAvailablePort(portToScan, closure)
} catch (BindException exception) {
log.debug("Failed to execute closure (try: $i/$maxRetryCount)", exception)
}
}
throw new NoPortAvailableException(minPortNumber, maxPortNumber)
}
private T executeLogicForAvailablePort(int portToScan, Closure closure) {
log.debug("Trying to execute closure with port [$portToScan]")
return closure(portToScan)
}
private void checkIfPortIsAvailable(int portToScan) {
ServerSocket socket = null
try {
socket = new ServerSocket(portToScan)
} finally {
socket?.close()
}
}
static class NoPortAvailableException extends RuntimeException {
protected NoPortAvailableException(int lowerBound, int upperBound) {
super("Could not find available port in range $lowerBound:$upperBound")
}
}
static class InvalidPortRange extends RuntimeException {
protected InvalidPortRange(int lowerBound, int upperBound) {
super("Invalid bounds exceptions, min port [$lowerBound] is greater to max port [$upperBound]")
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy