
net.apexes.commons.lang.NetworkTimeMillis Maven / Gradle / Ivy
package net.apexes.commons.lang;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author hedyn
*/
class NetworkTimeMillis {
private NetworkTimeMillis() {}
private static final Logger LOG = Logger.getLogger(NetworkTimeMillis.class.getName());
static long invoke(int timeoutMs, InetSocketAddress... addrs)
throws NetworkTimeMillisException, InterruptedException, ExecutionException, TimeoutException {
List addressList = new ArrayList<>();
for (InetSocketAddress addr : addrs) {
if (addr != null && addr.getAddress() != null) {
addressList.add(addr);
}
}
if (addressList.isEmpty()) {
throw new NetworkTimeMillisException("Unknown host.");
}
ExecutorService executor = Executors.newFixedThreadPool(addressList.size());
try {
return invoke(executor, timeoutMs, addressList);
} finally {
executor.shutdownNow();
}
}
static long invoke(ExecutorService executor, int timeoutMs, InetSocketAddress... addrs)
throws NetworkTimeMillisException, InterruptedException, ExecutionException, TimeoutException {
List addressList = new ArrayList<>();
for (InetSocketAddress addr : addrs) {
if (addr != null && addr.getAddress() != null) {
addressList.add(addr);
}
}
if (addressList.isEmpty()) {
throw new NetworkTimeMillisException("Unknown host.");
}
return invoke(executor, timeoutMs, addressList);
}
private static long invoke(ExecutorService executor, int timeoutMs, List addrs)
throws NetworkTimeMillisException, InterruptedException, ExecutionException, TimeoutException {
Checks.verifyNotNull(executor, "executor");
Checks.verifyNotEmpty(addrs, "addrs");
List resultList = new ArrayList<>();
List taskList = new ArrayList<>();
for (InetSocketAddress addr : addrs) {
taskList.add(new NetworkTimeMillisTask(addr, timeoutMs));
}
long timeout;
if (timeoutMs > 0) {
timeout = timeoutMs * 2L + 500;
} else {
timeout = timeoutMs;
}
List> futureList = executor.invokeAll(taskList);
for (Future future : futureList) {
resultList.add(future.get(timeout, TimeUnit.MILLISECONDS));
}
Map timeMap = new LinkedHashMap<>();
Map causeMap = new LinkedHashMap<>();
for (Result result : resultList) {
if (result.exception != null) {
causeMap.put(result.addr, result.exception);
} else if (result.timeMillis != 0) {
timeMap.put(result.addr, result.timeMillis());
}
}
if (addrs.size() == 1) {
if (timeMap.isEmpty()) {
throw new NetworkTimeMillisException(timeMap, causeMap);
}
return timeMap.get(addrs.get(0));
}
if (LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "networkTimeMillis: {0}", timeMap);
}
if (timeMap.size() >= 2) {
List timeList = new ArrayList<>(timeMap.values());
Long minDiff = null;
Long select1 = null;
Long select2 = null;
for (int i = timeList.size() - 1; i > 0; i--) {
for (int j = i - 1; j >= 0; j--) {
long value1 = timeList.get(i);
long value2 = timeList.get(j);
long diff = Math.abs(value1 - value2);
if (diff == 0) {
return value1;
}
if (minDiff == null || minDiff > diff) {
minDiff = diff;
select1 = value1;
select2 = value2;
}
}
}
if (minDiff != null && minDiff < 30000) {
return Math.max(select1, select2);
}
}
throw new NetworkTimeMillisException(timeMap, causeMap);
}
/**
*
* @author HeDYn
*/
private static class NetworkTimeMillisTask implements Callable {
private final InetSocketAddress addr;
private final int timeoutMs;
private NetworkTimeMillisTask(InetSocketAddress addr, int timeoutMs) {
this.addr = addr;
this.timeoutMs = timeoutMs;
}
@Override
public Result call() {
try {
long timeMillis = NTPTimeMillis.requestTime(addr.getAddress(), addr.getPort(), timeoutMs);
return new Result(addr, timeMillis);
} catch (Exception e) {
return new Result(addr, e);
}
}
}
private static class Result {
private final InetSocketAddress addr;
private final Long timeMillis;
private final long nanoTime;
private final Exception exception;
private Result(InetSocketAddress addr, long timeMillis) {
this.addr = addr;
this.timeMillis = timeMillis;
this.nanoTime = System.nanoTime();
this.exception = null;
}
private Result(InetSocketAddress addr, Exception exception) {
this.addr = addr;
this.timeMillis = null;
this.nanoTime = 0;
this.exception = exception;
}
long timeMillis() {
return timeMillis + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - nanoTime);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy