[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [exonerator/release] Use Java 8 date-time functionality.
commit 714862c3ecde23b44076c7dca42f8366714f8c11
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date: Sun Dec 16 11:39:42 2018 +0100
Use Java 8 date-time functionality.
Implements #28859.
---
.../exonerator/ExoneraTorDatabaseImporter.java | 38 +++++----
.../metrics/exonerator/QueryServlet.java | 94 +++++++++++-----------
2 files changed, 63 insertions(+), 69 deletions(-)
diff --git a/src/main/java/org/torproject/metrics/exonerator/ExoneraTorDatabaseImporter.java b/src/main/java/org/torproject/metrics/exonerator/ExoneraTorDatabaseImporter.java
index 3ed7c19..57eb5df 100644
--- a/src/main/java/org/torproject/metrics/exonerator/ExoneraTorDatabaseImporter.java
+++ b/src/main/java/org/torproject/metrics/exonerator/ExoneraTorDatabaseImporter.java
@@ -29,13 +29,14 @@ import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.util.Calendar;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
-import java.util.TimeZone;
import java.util.TreeMap;
/* Import Tor descriptors into the ExoneraTor database. */
@@ -131,10 +132,11 @@ public class ExoneraTorDatabaseImporter {
try {
if (lockFile.exists()) {
BufferedReader br = new BufferedReader(new FileReader(lockFile));
- long runStarted = Long.parseLong(br.readLine());
+ Instant runStarted = Instant.ofEpochMilli(Long.parseLong(
+ br.readLine()));
br.close();
- if (System.currentTimeMillis() - runStarted
- < 6L * 60L * 60L * 1000L) {
+ if (runStarted.plus(Duration.ofHours(6L))
+ .compareTo(Instant.now()) >= 0) {
logger.warn("File 'exonerator-lock' is less than 6 "
+ "hours old. Exiting.");
System.exit(1);
@@ -223,7 +225,8 @@ public class ExoneraTorDatabaseImporter {
/* Parse a consensus. */
private static void parseConsensus(RelayNetworkStatusConsensus consensus) {
- long validAfterMillis = consensus.getValidAfterMillis();
+ LocalDateTime validAfter = LocalDateTime.ofInstant(Instant.ofEpochMilli(
+ consensus.getValidAfterMillis()), ZoneOffset.UTC);
for (NetworkStatusEntry entry : consensus.getStatusEntries().values()) {
if (entry.getFlags().contains("Running")) {
String fingerprintBase64 = null;
@@ -248,26 +251,21 @@ public class ExoneraTorDatabaseImporter {
orAddresses.add(orAddressAndPort.substring(0,
orAddressAndPort.lastIndexOf(":")));
}
- importStatusentry(validAfterMillis, fingerprintBase64, nickname,
+ importStatusentry(validAfter, fingerprintBase64, nickname,
exit, orAddresses);
}
}
}
- /* UTC calendar for importing timestamps into the database. */
- private static Calendar calendarUTC = Calendar.getInstance(
- TimeZone.getTimeZone("UTC"));
-
/* Import a status entry with one or more OR addresses into the
* database. */
- private static void importStatusentry(long validAfterMillis,
+ private static void importStatusentry(LocalDateTime validAfter,
String fingerprintBase64, String nickname, Boolean exit,
Set<String> orAddresses) {
try {
for (String orAddress : orAddresses) {
insertStatusentryStatement.clearParameters();
- insertStatusentryStatement.setTimestamp(1,
- new Timestamp(validAfterMillis), calendarUTC);
+ insertStatusentryStatement.setObject(1, validAfter);
insertStatusentryStatement.setString(2, fingerprintBase64);
if (!orAddress.contains(":")) {
insertStatusentryStatement.setString(3, orAddress);
@@ -353,23 +351,23 @@ public class ExoneraTorDatabaseImporter {
exitAddressParts[2]);
String exitAddress24 = Hex.encodeHexString(
exitAddress24Bytes);
- long scannedMillis = e.getValue();
+ LocalDateTime scanned = LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(e.getValue()), ZoneOffset.UTC);
importExitlistentry(fingerprintBase64, exitAddress24, exitAddress,
- scannedMillis);
+ scanned);
}
}
}
/* Import an exit list entry into the database. */
private static void importExitlistentry(String fingerprintBase64,
- String exitAddress24, String exitAddress, long scannedMillis) {
+ String exitAddress24, String exitAddress, LocalDateTime scanned) {
try {
insertExitlistentryStatement.clearParameters();
insertExitlistentryStatement.setString(1, fingerprintBase64);
insertExitlistentryStatement.setString(2, exitAddress);
insertExitlistentryStatement.setString(3, exitAddress24);
- insertExitlistentryStatement.setTimestamp(4,
- new Timestamp(scannedMillis), calendarUTC);
+ insertExitlistentryStatement.setObject(4, scanned);
insertExitlistentryStatement.execute();
} catch (SQLException e) {
logger.error("Could not import exit list entry. Exiting.", e);
diff --git a/src/main/java/org/torproject/metrics/exonerator/QueryServlet.java b/src/main/java/org/torproject/metrics/exonerator/QueryServlet.java
index a807ad0..760e385 100644
--- a/src/main/java/org/torproject/metrics/exonerator/QueryServlet.java
+++ b/src/main/java/org/torproject/metrics/exonerator/QueryServlet.java
@@ -14,12 +14,15 @@ import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
-import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -47,7 +50,9 @@ public class QueryServlet extends HttpServlet {
private DataSource ds;
- private static final long MILLISECONDS_IN_A_DAY = 24L * 60L * 60L * 1000L;
+ private static final DateTimeFormatter validAfterTimeFormatter
+ = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+ .withZone(ZoneOffset.UTC);
@Override
public void init() {
@@ -88,7 +93,7 @@ public class QueryServlet extends HttpServlet {
"Missing timestamp parameter.");
return;
}
- Long timestamp = this.parseTimestampParameter(timestampParameter);
+ LocalDate timestamp = this.parseTimestampParameter(timestampParameter);
if (null == timestamp) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Invalid timestamp parameter.");
@@ -216,9 +221,9 @@ public class QueryServlet extends HttpServlet {
return address48;
}
- private Long parseTimestampParameter(
+ private LocalDate parseTimestampParameter(
String passedTimestampParameter) {
- Long timestamp = null;
+ LocalDate timestamp = null;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
dateFormat.setLenient(false);
@@ -226,8 +231,8 @@ public class QueryServlet extends HttpServlet {
&& passedTimestampParameter.length() > 0) {
String timestampParameter = passedTimestampParameter.trim();
try {
- timestamp = dateFormat.parse(timestampParameter).getTime();
- } catch (ParseException e) {
+ timestamp = LocalDate.parse(timestampParameter);
+ } catch (DateTimeException e) {
timestamp = null;
}
}
@@ -239,13 +244,13 @@ public class QueryServlet extends HttpServlet {
* it matches the day before the current system date (in UTC) or is even
* younger. */
private boolean checkTimestampTooRecent(String timestampParameter) {
- return timestampParameter.compareTo(ZonedDateTime.now(ZoneOffset.UTC)
- .toLocalDate().minusDays(1).toString()) >= 0;
+ return timestampParameter.compareTo(LocalDate.now(ZoneOffset.UTC)
+ .minusDays(1).toString()) >= 0;
}
/* Helper methods for querying the database. */
- private QueryResponse queryDatabase(String relayIp, long timestamp) {
+ private QueryResponse queryDatabase(String relayIp, LocalDate timestamp) {
/* Convert address to hex. */
String addressHex = !relayIp.contains(":")
@@ -255,23 +260,16 @@ public class QueryServlet extends HttpServlet {
}
String address24Hex = addressHex.substring(0, 6);
- /* Prepare formatting response items. */
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
- dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
- SimpleDateFormat validAfterTimeFormat = new SimpleDateFormat(
- "yyyy-MM-dd HH:mm:ss");
- validAfterTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
-
/* Store all dates contained in the query response in order to populate the
* {first|last}_date_in_database and relevant_statuses fields. */
- SortedSet<Long> allDates = new TreeSet<>();
+ SortedSet<LocalDate> allDates = new TreeSet<>();
/* Store all possible matches for the results table by base64-encoded
* fingerprint and valid-after time. This map is first populated by going
* through the result set and adding or updating map entries, so that
* there's one entry per fingerprint and valid-after time with one or more
* addresses. In a second step, exit addresses are added to map entries. */
- SortedMap<String, SortedMap<Long, QueryResponse.Match>>
+ SortedMap<String, SortedMap<LocalDateTime, QueryResponse.Match>>
matchesByFingerprintBase64AndValidAfter = new TreeMap<>();
/* Store all possible matches by address. This map has two purposes: First,
@@ -289,53 +287,50 @@ public class QueryServlet extends HttpServlet {
* result set and later added to the two maps above containing matches. The
* reason for separating these steps is that the result set may contain
* status entries and exit list entries in any specific order. */
- SortedMap<String, SortedMap<Long, String>>
+ SortedMap<String, SortedMap<LocalDateTime, String>>
exitAddressesByFingeprintBase64AndScanned = new TreeMap<>();
/* Make the database query to populate the sets and maps above. */
- final long requestedConnection = System.currentTimeMillis();
- Calendar utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ final Instant requestedConnection = Instant.now();
try (Connection conn = this.ds.getConnection()) {
try (CallableStatement cs = conn.prepareCall(
"{call search_by_date_address24(?, ?)}")) {
- cs.setDate(1, new java.sql.Date(timestamp), utcCalendar);
+ cs.setObject(1, timestamp);
cs.setString(2, address24Hex);
try (ResultSet rs = cs.executeQuery()) {
while (rs.next()) {
- java.sql.Date date = rs.getDate(1, utcCalendar);
+ LocalDate date = rs.getObject(1, LocalDate.class);
String fingerprintBase64 = rs.getString(2);
- java.sql.Timestamp scanned = rs.getTimestamp(3, utcCalendar);
+ LocalDateTime scanned = rs.getObject(3, LocalDateTime.class);
String exitAddress = rs.getString(4);
- java.sql.Timestamp validAfter = rs.getTimestamp(5, utcCalendar);
+ LocalDateTime validAfter = rs.getObject(5, LocalDateTime.class);
String nickname = rs.getString(6);
Boolean exit = rs.getBoolean(7);
String orAddress = rs.getString(8);
if (null != date) {
- allDates.add(date.getTime());
+ allDates.add(date);
} else if (null != scanned) {
- long scannedMillis = scanned.getTime();
exitAddressesByFingeprintBase64AndScanned.putIfAbsent(
fingerprintBase64, new TreeMap<>());
exitAddressesByFingeprintBase64AndScanned.get(fingerprintBase64)
- .put(scannedMillis, exitAddress);
+ .put(scanned, exitAddress);
} else if (null != validAfter) {
- long validAfterMillis = validAfter.getTime();
matchesByFingerprintBase64AndValidAfter.putIfAbsent(
fingerprintBase64, new TreeMap<>());
if (!matchesByFingerprintBase64AndValidAfter
- .get(fingerprintBase64).containsKey(validAfterMillis)) {
- String validAfterString = validAfterTimeFormat.format(
- validAfterMillis);
+ .get(fingerprintBase64).containsKey(validAfter)) {
+ String validAfterString = validAfter.format(
+ validAfterTimeFormatter);
String fingerprint = Hex.encodeHexString(Base64.decodeBase64(
fingerprintBase64 + "=")).toUpperCase();
matchesByFingerprintBase64AndValidAfter.get(fingerprintBase64)
- .put(validAfterMillis, new QueryResponse.Match(
+ .put(validAfter, new QueryResponse.Match(
validAfterString, new TreeSet<>(), fingerprint,
nickname, exit));
}
QueryResponse.Match match
= matchesByFingerprintBase64AndValidAfter
- .get(fingerprintBase64).get(validAfterMillis);
+ .get(fingerprintBase64).get(validAfter);
if (orAddress.contains(":")) {
match.addresses.add("[" + orAddress + "]");
} else {
@@ -349,8 +344,8 @@ public class QueryServlet extends HttpServlet {
this.logger.warn("Result set error. Returning 'null'.", e);
return null;
}
- this.logger.info("Returned a database connection to the pool after {}"
- + " millis.", System.currentTimeMillis() - requestedConnection);
+ this.logger.info("Returned a database connection to the pool after {}.",
+ Duration.between(requestedConnection, Instant.now()));
} catch (SQLException e) {
this.logger.warn("Callable statement error. Returning 'null'.", e);
return null;
@@ -361,7 +356,7 @@ public class QueryServlet extends HttpServlet {
}
/* Go through exit addresses and update possible matches. */
- for (Map.Entry<String, SortedMap<Long, String>> e
+ for (Map.Entry<String, SortedMap<LocalDateTime, String>> e
: exitAddressesByFingeprintBase64AndScanned.entrySet()) {
String fingerprintBase64 = e.getKey();
if (!matchesByFingerprintBase64AndValidAfter.containsKey(
@@ -373,13 +368,12 @@ public class QueryServlet extends HttpServlet {
* nearby matches. We'll just skip it. */
continue;
}
- for (Map.Entry<Long, String> e1 : e.getValue().entrySet()) {
- long scannedMillis = e1.getKey();
+ for (Map.Entry<LocalDateTime, String> e1 : e.getValue().entrySet()) {
+ LocalDateTime scanned = e1.getKey();
String exitAddress = e1.getValue();
for (QueryResponse.Match match
: matchesByFingerprintBase64AndValidAfter.get(fingerprintBase64)
- .subMap(scannedMillis, scannedMillis + MILLISECONDS_IN_A_DAY)
- .values()) {
+ .subMap(scanned, scanned.plusDays(1L)).values()) {
match.addresses.add(exitAddress);
matchesByAddress.putIfAbsent(exitAddress, new HashSet<>());
matchesByAddress.get(exitAddress).add(match);
@@ -390,13 +384,15 @@ public class QueryServlet extends HttpServlet {
/* Write all results to a new QueryResponse object. */
final QueryResponse response = new QueryResponse();
response.queryAddress = relayIp;
- response.queryDate = dateFormat.format(timestamp);
+ response.queryDate = timestamp.format(DateTimeFormatter.ISO_DATE);
if (!allDates.isEmpty()) {
- response.firstDateInDatabase = dateFormat.format(allDates.first());
- response.lastDateInDatabase = dateFormat.format(allDates.last());
+ response.firstDateInDatabase = allDates.first()
+ .format(DateTimeFormatter.ISO_DATE);
+ response.lastDateInDatabase = allDates.last()
+ .format(DateTimeFormatter.ISO_DATE);
response.relevantStatuses = allDates.contains(timestamp)
- || allDates.contains(timestamp - MILLISECONDS_IN_A_DAY)
- || allDates.contains(timestamp + MILLISECONDS_IN_A_DAY);
+ || allDates.contains(timestamp.minusDays(1L))
+ || allDates.contains(timestamp.plusDays(1L));
}
if (matchesByAddress.containsKey(relayIp)) {
List<QueryResponse.Match> matchesList
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits