All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.eventsourcing.hlc.NTPServerTimeProvider Maven / Gradle / Ivy

There is a newer version: 0.4.6
Show newest version
/**
 * Copyright (c) 2016, All Contributors (see CONTRIBUTORS file)
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.eventsourcing.hlc;

import com.google.common.util.concurrent.AbstractScheduledService;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.experimental.Accessors;
import org.apache.commons.net.ntp.NTPUDPClient;
import org.apache.commons.net.ntp.TimeStamp;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;

import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * NTPServerTimeProvider is a physical time provider that uses external NTP servers to fetch timestamp
 * periodically (currently hardcoded as 1 minute).
 * 

* By default, NTP servers are: *

* "0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org", "localhost" *

* NTPServerTimeProvider is an EventReducer Service and needs to be started prior * to using it as a PhysicalTimeProvider. */ @Component(property = "ntp.servers=localhost,0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org,3.pool.ntp.org") public class NTPServerTimeProvider extends AbstractScheduledService implements PhysicalTimeProvider { public static final int SO_TIMEOUT = 2000; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private static final String[] DEFAULT_NTP_SERVERS = {"localhost", "0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org"}; private NTPUDPClient client; private List servers; private TimeStamp timestamp; private long nano; @Setter @Accessors(fluent = true) private long delay = 30; @Setter @Accessors(fluent = true) private TimeUnit delayUnits = TimeUnit.MINUTES; @Activate protected void activate(ComponentContext ctx) throws SocketException { client = new NTPUDPClient(); String serversList = (String) ctx.getProperties().get("ntp.servers"); setServers(serversList.split(",")); setSocketTimeout(); } private void setSocketTimeout() throws SocketException { client.open(); client.setSoTimeout(SO_TIMEOUT); } /** * Creates NTPServerTimeProvider with default NTP servers * * @throws UnknownHostException Throws UnknownHostException for the first unresolved host, if no hosts were resolvable */ public NTPServerTimeProvider() throws UnknownHostException, SocketException { this(DEFAULT_NTP_SERVERS); } @Override protected void startUp() throws Exception { update(); } @Override protected void runOneIteration() throws Exception { update(); } @Override protected Scheduler scheduler() { return Scheduler.newFixedDelaySchedule(0, delay, delayUnits); } /** * Creates NTPServerTimeProvider with a custom list of NTP server addresses * * @param ntpServers Array of custom NTP server addresses * @throws UnknownHostException Throws UnknownHostException for the first unresolved host, if no hosts were resolvable */ public NTPServerTimeProvider(String[] ntpServers) throws UnknownHostException, SocketException { client = new NTPUDPClient(); setServers(ntpServers); if (servers.isEmpty()) { throw new UnknownHostException(ntpServers[0]); } setSocketTimeout(); } protected void setServers(String[] ntpServers) { servers = Arrays.asList(ntpServers).stream().map(server -> { try { return InetAddress.getByName(server); } catch (UnknownHostException e) { return null; } }).filter(address -> address != null).collect(Collectors.toList()); } synchronized private void update() { InetAddress server = servers.remove(0); try { timestamp = client.getTime(server).getMessage().getTransmitTimeStamp(); nano = System.nanoTime(); servers.add(0, server); // add back to the beginning } catch (IOException e) { servers.add(server); // add to the end of the list } } TimeStamp getTimestamp() throws TimeoutException { if (timestamp == null) { throw new TimeoutException(); } TimeStamp ts = new TimeStamp(timestamp.ntpValue()); long fraction = ts.getFraction(); long seconds = ts.getSeconds(); long nanoTime = System.nanoTime(); long l = (nanoTime - nano) / 1_000_000_000; double v = (nanoTime - nano) / 1_000_000_000.0 - l; long i = (long) (v * 1_000_000_000); long fraction_ = fraction + i; if (fraction_ >= 1_000_000_000) { fraction_ -= 1_000_000_000; l++; } return new TimeStamp((seconds + l) << 32 | fraction_); } @Override @SneakyThrows public long getPhysicalTime() { return getTimestamp().ntpValue(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy