From 69c9988404e19f1a5b306e28a90227891de818bb Mon Sep 17 00:00:00 2001 From: Athou Date: Mon, 8 Jan 2024 20:42:45 +0100 Subject: [PATCH] migrate from java.util.Date to java.time --- .../com/commafeed/CommaFeedApplication.java | 18 +++++-- .../com/commafeed/CommaFeedConfiguration.java | 10 ++-- .../com/commafeed/backend/dao/FeedDAO.java | 8 +-- .../commafeed/backend/dao/FeedEntryDAO.java | 4 +- .../backend/dao/FeedEntryStatusDAO.java | 22 ++++---- .../commafeed/backend/feed/FeedFetcher.java | 9 ++-- .../backend/feed/FeedRefreshEngine.java | 11 ++-- .../feed/FeedRefreshIntervalCalculator.java | 50 +++++++++---------- .../backend/feed/FeedRefreshUpdater.java | 4 +- .../backend/feed/FeedRefreshWorker.java | 8 +-- .../backend/feed/parser/FeedParser.java | 34 ++++++------- .../backend/feed/parser/FeedParserResult.java | 6 +-- .../com/commafeed/backend/model/Feed.java | 20 ++++---- .../commafeed/backend/model/FeedEntry.java | 12 ++--- .../backend/model/FeedEntryStatus.java | 12 ++--- .../com/commafeed/backend/model/User.java | 16 +++--- .../service/DatabaseCleaningService.java | 6 +-- .../backend/service/FeedEntryService.java | 18 +++---- .../backend/service/FeedService.java | 6 +-- .../service/FeedSubscriptionService.java | 6 +-- .../backend/service/UserService.java | 4 +- .../service/internal/PostLoginActivities.java | 11 ++-- .../backend/task/OldEntriesCleanupTask.java | 7 ++- .../backend/task/OldStatusesCleanupTask.java | 4 +- .../com/commafeed/frontend/model/Entry.java | 7 +-- .../frontend/model/Subscription.java | 12 ++--- .../commafeed/frontend/model/UnreadCount.java | 6 +-- .../commafeed/frontend/model/UserModel.java | 6 +-- .../frontend/resource/CategoryREST.java | 8 +-- .../commafeed/frontend/resource/FeedREST.java | 9 ++-- .../commafeed/frontend/resource/UserREST.java | 8 +-- .../frontend/resource/fever/FeverREST.java | 11 ++-- .../backend/feed/FeedFetcherTest.java | 4 +- .../com/commafeed/e2e/PlaywrightTestBase.java | 6 +-- .../commafeed/integration/rest/FeedIT.java | 26 +++++----- 35 files changed, 203 insertions(+), 206 deletions(-) diff --git a/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java b/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java index 77aa20a2..d267160a 100644 --- a/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java +++ b/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java @@ -1,7 +1,7 @@ package com.commafeed; import java.io.IOException; -import java.util.Date; +import java.time.Instant; import java.util.EnumSet; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; @@ -42,8 +42,10 @@ import com.commafeed.frontend.servlet.RobotsTxtDisallowAllServlet; import com.commafeed.frontend.session.SessionHelperFactoryProvider; import com.commafeed.frontend.ws.WebSocketConfigurator; import com.commafeed.frontend.ws.WebSocketEndpoint; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; @@ -76,7 +78,7 @@ public class CommaFeedApplication extends Application { public static final String USERNAME_ADMIN = "admin"; public static final String USERNAME_DEMO = "demo"; - public static final Date STARTUP_TIME = new Date(); + public static final Instant STARTUP_TIME = Instant.now(); private HibernateBundle hibernateBundle; private WebsocketBundle websocketBundle; @@ -89,8 +91,7 @@ public class CommaFeedApplication extends Application { @Override public void initialize(Bootstrap bootstrap) { configureEnvironmentSubstitutor(bootstrap); - - bootstrap.getObjectMapper().registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false)); + configureObjectMapper(bootstrap.getObjectMapper()); bootstrap.addBundle(websocketBundle = new WebsocketBundle<>()); bootstrap.addBundle(hibernateBundle = new HibernateBundle<>(AbstractModel.class, Feed.class, FeedCategory.class, FeedEntry.class, @@ -134,6 +135,15 @@ public class CommaFeedApplication extends Application { bootstrap.setConfigurationSourceProvider(buildEnvironmentSubstitutor(bootstrap)); } + private static void configureObjectMapper(ObjectMapper objectMapper) { + // read and write instants as milliseconds instead of nanoseconds + objectMapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false) + .configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false); + + // add support for serializing metrics + objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false)); + } + private static EnvironmentSubstitutor buildEnvironmentSubstitutor(Bootstrap bootstrap) { // enable config.yml string substitution // e.g. having a custom config.yml file with app.session.path=${SOME_ENV_VAR} will substitute SOME_ENV_VAR diff --git a/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java b/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java index 418190cc..f1ddab63 100644 --- a/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java +++ b/commafeed-server/src/main/java/com/commafeed/CommaFeedConfiguration.java @@ -1,10 +1,9 @@ package com.commafeed; -import java.util.Date; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ResourceBundle; -import org.apache.commons.lang3.time.DateUtils; - import com.commafeed.backend.cache.RedisPoolFactory; import com.commafeed.frontend.session.SessionHandlerFactory; import com.fasterxml.jackson.annotation.JsonProperty; @@ -175,9 +174,8 @@ public class CommaFeedConfiguration extends Configuration implements WebsocketBu private Duration treeReloadInterval = Duration.seconds(30); - public Date getUnreadThreshold() { - int keepStatusDays = getKeepStatusDays(); - return keepStatusDays > 0 ? DateUtils.addDays(new Date(), -1 * keepStatusDays) : null; + public Instant getUnreadThreshold() { + return getKeepStatusDays() > 0 ? Instant.now().minus(getKeepStatusDays(), ChronoUnit.DAYS) : null; } } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedDAO.java b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedDAO.java index f91eb0e8..21b7c1a2 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedDAO.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedDAO.java @@ -1,6 +1,6 @@ package com.commafeed.backend.dao; -import java.util.Date; +import java.time.Instant; import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -26,8 +26,8 @@ public class FeedDAO extends GenericDAO { super(sessionFactory); } - public List findNextUpdatable(int count, Date lastLoginThreshold) { - JPAQuery query = query().selectFrom(feed).where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(new Date()))); + public List findNextUpdatable(int count, Instant lastLoginThreshold) { + JPAQuery query = query().selectFrom(feed).where(feed.disabledUntil.isNull().or(feed.disabledUntil.lt(Instant.now()))); if (lastLoginThreshold != null) { query.where(JPAExpressions.selectOne() .from(subscription) @@ -39,7 +39,7 @@ public class FeedDAO extends GenericDAO { return query.orderBy(feed.disabledUntil.asc()).limit(count).fetch(); } - public void setDisabledUntil(List feedIds, Date date) { + public void setDisabledUntil(List feedIds, Instant date) { updateQuery(feed).set(feed.disabledUntil, date).where(feed.id.in(feedIds)).execute(); } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java index bc914e07..04494f92 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryDAO.java @@ -1,6 +1,6 @@ package com.commafeed.backend.dao; -import java.util.Date; +import java.time.Instant; import java.util.List; import org.hibernate.SessionFactory; @@ -49,7 +49,7 @@ public class FeedEntryDAO extends GenericDAO { /** * Delete entries older than a certain date */ - public int deleteEntriesOlderThan(Date olderThan, long max) { + public int deleteEntriesOlderThan(Instant olderThan, long max) { List list = query().selectFrom(entry).where(entry.updated.lt(olderThan)).orderBy(entry.updated.asc()).limit(max).fetch(); return delete(list); } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java index 1b8c8215..f0dbf1e8 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/dao/FeedEntryStatusDAO.java @@ -1,8 +1,8 @@ package com.commafeed.backend.dao; +import java.time.Instant; import java.util.ArrayList; import java.util.Comparator; -import java.util.Date; import java.util.List; import org.apache.commons.collections4.CollectionUtils; @@ -73,8 +73,8 @@ public class FeedEntryStatusDAO extends GenericDAO { private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) { if (status == null) { - Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold(); - boolean read = unreadThreshold != null && entry.getUpdated().before(unreadThreshold); + Instant unreadThreshold = config.getApplicationSettings().getUnreadThreshold(); + boolean read = unreadThreshold != null && entry.getUpdated().isBefore(unreadThreshold); status = new FeedEntryStatus(user, sub, entry); status.setRead(read); status.setMarkable(!read); @@ -90,7 +90,8 @@ public class FeedEntryStatusDAO extends GenericDAO { return status; } - public List findStarred(User user, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent) { + public List findStarred(User user, Instant newerThan, int offset, int limit, ReadingOrder order, + boolean includeContent) { JPAQuery query = query().selectFrom(status).where(status.user.eq(user), status.starred.isTrue()); if (newerThan != null) { query.where(status.entryInserted.gt(newerThan)); @@ -114,7 +115,8 @@ public class FeedEntryStatusDAO extends GenericDAO { } private JPAQuery buildQuery(User user, FeedSubscription sub, boolean unreadOnly, List keywords, - Date newerThan, int offset, int limit, ReadingOrder order, FeedEntryStatus last, String tag, Long minEntryId, Long maxEntryId) { + Instant newerThan, int offset, int limit, ReadingOrder order, FeedEntryStatus last, String tag, Long minEntryId, + Long maxEntryId) { JPAQuery query = query().selectFrom(entry).where(entry.feed.eq(sub.getFeed())); @@ -139,7 +141,7 @@ public class FeedEntryStatusDAO extends GenericDAO { or.or(status.read.isFalse()); query.where(or); - Date unreadThreshold = config.getApplicationSettings().getUnreadThreshold(); + Instant unreadThreshold = config.getApplicationSettings().getUnreadThreshold(); if (unreadThreshold != null) { query.where(entry.updated.goe(unreadThreshold)); } @@ -193,7 +195,7 @@ public class FeedEntryStatusDAO extends GenericDAO { } public List findBySubscriptions(User user, List subs, boolean unreadOnly, - List keywords, Date newerThan, int offset, int limit, ReadingOrder order, boolean includeContent, + List keywords, Instant newerThan, int offset, int limit, ReadingOrder order, boolean includeContent, boolean onlyIds, String tag, Long minEntryId, Long maxEntryId) { int capacity = offset + limit; @@ -208,7 +210,7 @@ public class FeedEntryStatusDAO extends GenericDAO { for (Tuple tuple : tuples) { Long id = tuple.get(entry.id); - Date updated = tuple.get(entry.updated); + Instant updated = tuple.get(entry.updated); Long statusId = tuple.get(status.id); FeedEntryContent content = new FeedEntryContent(); @@ -260,7 +262,7 @@ public class FeedEntryStatusDAO extends GenericDAO { List tuples = query.select(entry.count(), entry.updated.max()).fetch(); for (Tuple tuple : tuples) { Long count = tuple.get(entry.count()); - Date updated = tuple.get(entry.updated.max()); + Instant updated = tuple.get(entry.updated.max()); uc = new UnreadCount(subscription.getId(), count == null ? 0 : count, updated); } return uc; @@ -276,7 +278,7 @@ public class FeedEntryStatusDAO extends GenericDAO { return results; } - public long deleteOldStatuses(Date olderThan, int limit) { + public long deleteOldStatuses(Instant olderThan, int limit) { List ids = query().select(status.id) .from(status) .where(status.entryInserted.lt(olderThan), status.starred.isFalse()) diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedFetcher.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedFetcher.java index 592d5e6a..7352930e 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedFetcher.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedFetcher.java @@ -1,7 +1,7 @@ package com.commafeed.backend.feed; import java.io.IOException; -import java.util.Date; +import java.time.Instant; import java.util.Set; import org.apache.commons.codec.binary.StringUtils; @@ -32,8 +32,8 @@ public class FeedFetcher { private final HttpGetter getter; private final Set urlProviders; - public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag, Date lastPublishedDate, - String lastContentHash) throws FeedException, IOException, NotModifiedException { + public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag, + Instant lastPublishedDate, String lastContentHash) throws FeedException, IOException, NotModifiedException { log.debug("Fetching feed {}", feedUrl); int timeout = 20000; @@ -76,8 +76,7 @@ public class FeedFetcher { etagHeaderValueChanged ? result.getETag() : null); } - if (lastPublishedDate != null && parserResult.lastPublishedDate() != null - && lastPublishedDate.getTime() == parserResult.lastPublishedDate().getTime()) { + if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) { log.debug("publishedDate not modified: {}", feedUrl); throw new NotModifiedException("publishedDate not modified", lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null, diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshEngine.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshEngine.java index 291d3061..9f39cbf0 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshEngine.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshEngine.java @@ -1,6 +1,7 @@ package com.commafeed.backend.feed; -import java.util.Date; +import java.time.Duration; +import java.time.Instant; import java.util.List; import java.util.concurrent.BlockingDeque; import java.util.concurrent.CompletableFuture; @@ -11,8 +12,6 @@ import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.time.DateUtils; - import com.codahale.metrics.Gauge; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; @@ -166,12 +165,12 @@ public class FeedRefreshEngine implements Managed { private List getNextUpdatableFeeds(int max) { return unitOfWork.call(() -> { - Date lastLoginThreshold = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad()) - ? DateUtils.addDays(new Date(), -30) + Instant lastLoginThreshold = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad()) + ? Instant.now().minus(Duration.ofDays(30)) : null; List feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold); // update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable() - Date nextUpdateDate = DateUtils.addMinutes(new Date(), config.getApplicationSettings().getRefreshIntervalMinutes()); + Instant nextUpdateDate = Instant.now().plus(Duration.ofMinutes(config.getApplicationSettings().getRefreshIntervalMinutes())); feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate); return feeds; }); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshIntervalCalculator.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshIntervalCalculator.java index 3d19ca89..d4097332 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshIntervalCalculator.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshIntervalCalculator.java @@ -1,8 +1,8 @@ package com.commafeed.backend.feed; -import java.util.Date; - -import org.apache.commons.lang3.time.DateUtils; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import com.commafeed.CommaFeedConfiguration; @@ -21,61 +21,59 @@ public class FeedRefreshIntervalCalculator { this.refreshIntervalMinutes = config.getApplicationSettings().getRefreshIntervalMinutes(); } - public Date onFetchSuccess(Date publishedDate, Long averageEntryInterval) { - Date defaultRefreshInterval = getDefaultRefreshInterval(); + public Instant onFetchSuccess(Instant publishedDate, Long averageEntryInterval) { + Instant defaultRefreshInterval = getDefaultRefreshInterval(); return heavyLoad ? computeRefreshIntervalForHeavyLoad(publishedDate, averageEntryInterval, defaultRefreshInterval) : defaultRefreshInterval; } - public Date onFeedNotModified(Date publishedDate, Long averageEntryInterval) { - Date defaultRefreshInterval = getDefaultRefreshInterval(); - return heavyLoad ? computeRefreshIntervalForHeavyLoad(publishedDate, averageEntryInterval, defaultRefreshInterval) - : defaultRefreshInterval; + public Instant onFeedNotModified(Instant publishedDate, Long averageEntryInterval) { + return onFetchSuccess(publishedDate, averageEntryInterval); } - public Date onFetchError(int errorCount) { + public Instant onFetchError(int errorCount) { int retriesBeforeDisable = 3; if (errorCount < retriesBeforeDisable || !heavyLoad) { return getDefaultRefreshInterval(); } int disabledHours = Math.min(24 * 7, errorCount - retriesBeforeDisable + 1); - return DateUtils.addHours(new Date(), disabledHours); + return Instant.now().plus(Duration.ofHours(disabledHours)); } - private Date getDefaultRefreshInterval() { - return DateUtils.addMinutes(new Date(), refreshIntervalMinutes); + private Instant getDefaultRefreshInterval() { + return Instant.now().plus(Duration.ofMinutes(refreshIntervalMinutes)); } - private Date computeRefreshIntervalForHeavyLoad(Date publishedDate, Long averageEntryInterval, Date defaultRefreshInterval) { - Date now = new Date(); + private Instant computeRefreshIntervalForHeavyLoad(Instant publishedDate, Long averageEntryInterval, Instant defaultRefreshInterval) { + Instant now = Instant.now(); if (publishedDate == null) { // feed with no entries, recheck in 24 hours - return DateUtils.addHours(now, 24); - } else if (publishedDate.before(DateUtils.addMonths(now, -1))) { + return now.plus(Duration.ofHours(24)); + } else if (ChronoUnit.DAYS.between(publishedDate, now) >= 30) { // older than a month, recheck in 24 hours - return DateUtils.addHours(now, 24); - } else if (publishedDate.before(DateUtils.addDays(now, -14))) { + return now.plus(Duration.ofHours(24)); + } else if (ChronoUnit.DAYS.between(publishedDate, now) >= 14) { // older than two weeks, recheck in 12 hours - return DateUtils.addHours(now, 12); - } else if (publishedDate.before(DateUtils.addDays(now, -7))) { + return now.plus(Duration.ofHours(12)); + } else if (ChronoUnit.DAYS.between(publishedDate, now) >= 7) { // older than a week, recheck in 6 hours - return DateUtils.addHours(now, 6); + return now.plus(Duration.ofHours(6)); } else if (averageEntryInterval != null) { // use average time between entries to decide when to refresh next, divided by factor int factor = 2; // not more than 6 hours - long date = Math.min(DateUtils.addHours(now, 6).getTime(), now.getTime() + averageEntryInterval / factor); + long date = Math.min(now.plus(Duration.ofHours(6)).toEpochMilli(), now.toEpochMilli() + averageEntryInterval / factor); // not less than default refresh interval - date = Math.max(defaultRefreshInterval.getTime(), date); + date = Math.max(defaultRefreshInterval.toEpochMilli(), date); - return new Date(date); + return Instant.ofEpochMilli(date); } else { // unknown case, recheck in 24 hours - return DateUtils.addHours(now, 24); + return now.plus(Duration.ofHours(24)); } } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshUpdater.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshUpdater.java index 9ee4b5f8..7cb4f6b7 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshUpdater.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshUpdater.java @@ -1,8 +1,8 @@ package com.commafeed.backend.feed; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -161,7 +161,7 @@ public class FeedRefreshUpdater implements Managed { if (!processed) { // requeue asap - feed.setDisabledUntil(new Date(0)); + feed.setDisabledUntil(Instant.EPOCH); } if (insertedAtLeastOneEntry) { diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshWorker.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshWorker.java index aa0491c6..af446f6a 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshWorker.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/FeedRefreshWorker.java @@ -1,12 +1,12 @@ package com.commafeed.backend.feed; +import java.time.Duration; +import java.time.Instant; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Optional; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.DateUtils; import com.codahale.metrics.Meter; import com.codahale.metrics.MetricRegistry; @@ -58,8 +58,8 @@ public class FeedRefreshWorker { Integer maxEntriesAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays(); if (maxEntriesAgeDays > 0) { - Date threshold = DateUtils.addDays(new Date(), -1 * maxEntriesAgeDays); - entries = entries.stream().filter(entry -> entry.updated().after(threshold)).toList(); + Instant threshold = Instant.now().minus(Duration.ofDays(maxEntriesAgeDays)); + entries = entries.stream().filter(entry -> entry.updated().isAfter(threshold)).toList(); } String urlAfterRedirect = result.urlAfterRedirect(); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParser.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParser.java index c31a0c71..0f49ad85 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParser.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParser.java @@ -3,6 +3,7 @@ package com.commafeed.backend.feed.parser; import java.io.StringReader; import java.nio.charset.Charset; import java.text.DateFormat; +import java.time.Instant; import java.util.ArrayList; import java.util.Comparator; import java.util.Date; @@ -50,8 +51,8 @@ public class FeedParser { private static final Namespace ATOM_10_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom"); - private static final Date START = new Date(86400000); - private static final Date END = new Date(1000L * Integer.MAX_VALUE - 86400000); + private static final Instant START = Instant.ofEpochMilli(86400000); + private static final Instant END = Instant.ofEpochMilli(1000L * Integer.MAX_VALUE - 86400000); private final EncodingDetector encodingDetector; private final FeedCleaner feedCleaner; @@ -72,9 +73,9 @@ public class FeedParser { String title = feed.getTitle(); String link = feed.getLink(); List entries = buildEntries(feed, feedUrl); - Date lastEntryDate = entries.stream().findFirst().map(Entry::updated).orElse(null); - Date lastPublishedDate = validateDate(feed.getPublishedDate(), false); - if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.before(lastEntryDate)) { + Instant lastEntryDate = entries.stream().findFirst().map(Entry::updated).orElse(null); + Instant lastPublishedDate = toValidInstant(feed.getPublishedDate(), false); + if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.isBefore(lastEntryDate)) { lastPublishedDate = lastEntryDate; } Long averageEntryInterval = averageTimeBetweenEntries(entries); @@ -122,7 +123,7 @@ public class FeedParser { url = guid; } - Date updated = buildEntryUpdateDate(item); + Instant updated = buildEntryUpdateDate(item); Content content = buildContent(item); entries.add(new Entry(guid, url, updated, content)); @@ -153,15 +154,12 @@ public class FeedParser { return new Enclosure(enclosure.getUrl(), enclosure.getType()); } - private Date buildEntryUpdateDate(SyndEntry item) { + private Instant buildEntryUpdateDate(SyndEntry item) { Date date = item.getUpdatedDate(); if (date == null) { date = item.getPublishedDate(); } - if (date == null) { - date = new Date(); - } - return validateDate(date, true); + return toValidInstant(date, true); } private String buildEntryUrl(SyndFeed feed, String feedUrl, SyndEntry item) { @@ -176,19 +174,21 @@ public class FeedParser { return FeedUtils.toAbsoluteUrl(url, feedLink, feedUrl); } - private Date validateDate(Date date, boolean nullToNow) { - Date now = new Date(); + private Instant toValidInstant(Date date, boolean nullToNow) { + Instant now = Instant.now(); if (date == null) { return nullToNow ? now : null; } - if (date.before(START) || date.after(END)) { + + Instant instant = date.toInstant(); + if (instant.isBefore(START) || instant.isAfter(END)) { return now; } - if (date.after(now)) { + if (instant.isAfter(now)) { return now; } - return date; + return instant; } private String getContent(SyndEntry item) { @@ -262,7 +262,7 @@ public class FeedParser { SummaryStatistics stats = new SummaryStatistics(); for (int i = 0; i < entries.size() - 1; i++) { - long diff = Math.abs(entries.get(i).updated().getTime() - entries.get(i + 1).updated().getTime()); + long diff = Math.abs(entries.get(i).updated().toEpochMilli() - entries.get(i + 1).updated().toEpochMilli()); stats.addValue(diff); } return (long) stats.getMean(); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParserResult.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParserResult.java index 912afee0..ad3e72f1 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParserResult.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/parser/FeedParserResult.java @@ -1,11 +1,11 @@ package com.commafeed.backend.feed.parser; -import java.util.Date; +import java.time.Instant; import java.util.List; -public record FeedParserResult(String title, String link, Date lastPublishedDate, Long averageEntryInterval, Date lastEntryDate, +public record FeedParserResult(String title, String link, Instant lastPublishedDate, Long averageEntryInterval, Instant lastEntryDate, List entries) { - public record Entry(String guid, String url, Date updated, Content content) { + public record Entry(String guid, String url, Instant updated, Content content) { } public record Content(String title, String content, String author, String categories, Enclosure enclosure, Media media) { diff --git a/commafeed-server/src/main/java/com/commafeed/backend/model/Feed.java b/commafeed-server/src/main/java/com/commafeed/backend/model/Feed.java index 06a77c20..86ad8895 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/model/Feed.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/model/Feed.java @@ -1,12 +1,10 @@ package com.commafeed.backend.model; -import java.util.Date; +import java.time.Instant; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; import lombok.Getter; import lombok.Setter; @@ -44,20 +42,20 @@ public class Feed extends AbstractModel { /** * Last time we tried to fetch the feed */ - @Temporal(TemporalType.TIMESTAMP) - private Date lastUpdated; + @Column + private Instant lastUpdated; /** * Last publishedDate value in the feed */ - @Temporal(TemporalType.TIMESTAMP) - private Date lastPublishedDate; + @Column + private Instant lastPublishedDate; /** * date of the last entry of the feed */ - @Temporal(TemporalType.TIMESTAMP) - private Date lastEntryDate; + @Column + private Instant lastEntryDate; /** * error message while retrieving the feed @@ -73,8 +71,8 @@ public class Feed extends AbstractModel { /** * feed refresh is disabled until this date */ - @Temporal(TemporalType.TIMESTAMP) - private Date disabledUntil; + @Column + private Instant disabledUntil; /** * http header returned by the feed diff --git a/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntry.java b/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntry.java index eaadbfb2..b75520f1 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntry.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntry.java @@ -1,6 +1,6 @@ package com.commafeed.backend.model; -import java.util.Date; +import java.time.Instant; import java.util.Set; import jakarta.persistence.CascadeType; @@ -11,8 +11,6 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; import lombok.Getter; import lombok.Setter; @@ -39,11 +37,11 @@ public class FeedEntry extends AbstractModel { @Column(length = 2048) private String url; - @Temporal(TemporalType.TIMESTAMP) - private Date inserted; + @Column + private Instant inserted; - @Temporal(TemporalType.TIMESTAMP) - private Date updated; + @Column + private Instant updated; @OneToMany(mappedBy = "entry", cascade = CascadeType.REMOVE) private Set statuses; diff --git a/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java b/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java index 7f6fb0ef..899267ad 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/model/FeedEntryStatus.java @@ -1,7 +1,7 @@ package com.commafeed.backend.model; +import java.time.Instant; import java.util.ArrayList; -import java.util.Date; import java.util.List; import jakarta.persistence.Column; @@ -10,8 +10,6 @@ import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; import jakarta.persistence.Transient; import lombok.Getter; import lombok.Setter; @@ -49,11 +47,11 @@ public class FeedEntryStatus extends AbstractModel { @JoinColumn(nullable = false) private User user; - @Temporal(TemporalType.TIMESTAMP) - private Date entryInserted; + @Column + private Instant entryInserted; - @Temporal(TemporalType.TIMESTAMP) - private Date entryUpdated; + @Column + private Instant entryUpdated; public FeedEntryStatus() { diff --git a/commafeed-server/src/main/java/com/commafeed/backend/model/User.java b/commafeed-server/src/main/java/com/commafeed/backend/model/User.java index 8f517591..18595ffa 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/model/User.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/model/User.java @@ -1,12 +1,10 @@ package com.commafeed.backend.model; -import java.util.Date; +import java.time.Instant; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Table; -import jakarta.persistence.Temporal; -import jakarta.persistence.TemporalType; import lombok.Getter; import lombok.Setter; @@ -35,15 +33,15 @@ public class User extends AbstractModel { @Column(nullable = false) private boolean disabled; - @Temporal(TemporalType.TIMESTAMP) - private Date lastLogin; + @Column + private Instant lastLogin; - @Temporal(TemporalType.TIMESTAMP) - private Date created; + @Column + private Instant created; @Column(length = 40) private String recoverPasswordToken; - @Temporal(TemporalType.TIMESTAMP) - private Date recoverPasswordTokenDate; + @Column + private Instant recoverPasswordTokenDate; } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/DatabaseCleaningService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/DatabaseCleaningService.java index 8da9ffd5..336a05cf 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/DatabaseCleaningService.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/DatabaseCleaningService.java @@ -1,6 +1,6 @@ package com.commafeed.backend.service; -import java.util.Date; +import java.time.Instant; import java.util.List; import com.codahale.metrics.Meter; @@ -106,7 +106,7 @@ public class DatabaseCleaningService { log.info("cleanup done: {} entries for feeds exceeding capacity deleted", total); } - public void cleanEntriesOlderThan(final Date olderThan) { + public void cleanEntriesOlderThan(final Instant olderThan) { log.info("cleaning old entries"); long total = 0; long deleted; @@ -119,7 +119,7 @@ public class DatabaseCleaningService { log.info("cleanup done: {} old entries deleted", total); } - public void cleanStatusesOlderThan(final Date olderThan) { + public void cleanStatusesOlderThan(final Instant olderThan) { log.info("cleaning old read statuses"); long total = 0; long deleted; diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedEntryService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedEntryService.java index 5bff1883..98b708a9 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedEntryService.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedEntryService.java @@ -1,6 +1,6 @@ package com.commafeed.backend.service; -import java.util.Date; +import java.time.Instant; import java.util.List; import org.apache.commons.codec.digest.DigestUtils; @@ -73,7 +73,7 @@ public class FeedEntryService { entry.setGuidHash(guidHash); entry.setUrl(FeedUtils.truncate(e.url(), 2048)); entry.setUpdated(e.updated()); - entry.setInserted(new Date()); + entry.setInserted(Instant.now()); entry.setFeed(feed); entry.setContent(feedEntryContentService.findOrCreate(e.content(), feed.getLink())); @@ -117,7 +117,7 @@ public class FeedEntryService { feedEntryStatusDAO.saveOrUpdate(status); } - public void markSubscriptionEntries(User user, List subscriptions, Date olderThan, Date insertedBefore, + public void markSubscriptionEntries(User user, List subscriptions, Instant olderThan, Instant insertedBefore, List keywords) { List statuses = feedEntryStatusDAO.findBySubscriptions(user, subscriptions, true, keywords, null, -1, -1, null, false, false, null, null, null); @@ -126,18 +126,18 @@ public class FeedEntryService { cache.invalidateUserRootCategory(user); } - public void markStarredEntries(User user, Date olderThan, Date insertedBefore) { + public void markStarredEntries(User user, Instant olderThan, Instant insertedBefore) { List statuses = feedEntryStatusDAO.findStarred(user, null, -1, -1, null, false); markList(statuses, olderThan, insertedBefore); } - private void markList(List statuses, Date olderThan, Date insertedBefore) { + private void markList(List statuses, Instant olderThan, Instant insertedBefore) { List statusesToMark = statuses.stream().filter(s -> { - Date entryDate = s.getEntry().getUpdated(); - return olderThan == null || entryDate == null || entryDate.before(olderThan); + Instant entryDate = s.getEntry().getUpdated(); + return olderThan == null || entryDate == null || entryDate.isBefore(olderThan); }).filter(s -> { - Date insertedDate = s.getEntry().getInserted(); - return insertedBefore == null || insertedDate == null || insertedDate.before(insertedBefore); + Instant insertedDate = s.getEntry().getInserted(); + return insertedBefore == null || insertedDate == null || insertedDate.isBefore(insertedBefore); }).toList(); statusesToMark.forEach(s -> s.setRead(true)); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedService.java index f8e6bb92..209189e2 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedService.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedService.java @@ -1,7 +1,7 @@ package com.commafeed.backend.service; import java.io.IOException; -import java.util.Date; +import java.time.Instant; import java.util.Set; import org.apache.commons.codec.digest.DigestUtils; @@ -45,7 +45,7 @@ public class FeedService { feed.setUrl(url); feed.setNormalizedUrl(normalizedUrl); feed.setNormalizedUrlHash(normalizedUrlHash); - feed.setDisabledUntil(new Date(0)); + feed.setDisabledUntil(Instant.EPOCH); feedDAO.saveOrUpdate(feed); } return feed; @@ -55,7 +55,7 @@ public class FeedService { String normalized = FeedUtils.normalizeURL(feed.getUrl()); feed.setNormalizedUrl(normalized); feed.setNormalizedUrlHash(DigestUtils.sha1Hex(normalized)); - feed.setLastUpdated(new Date()); + feed.setLastUpdated(Instant.now()); feed.setEtagHeader(FeedUtils.truncate(feed.getEtagHeader(), 255)); feedDAO.saveOrUpdate(feed); } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedSubscriptionService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedSubscriptionService.java index beb49643..3cbbb658 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/FeedSubscriptionService.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/FeedSubscriptionService.java @@ -1,6 +1,6 @@ package com.commafeed.backend.service; -import java.util.Date; +import java.time.Instant; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -110,8 +110,8 @@ public class FeedSubscriptionService { public void refreshAllUpForRefresh(User user) { List subs = feedSubscriptionDAO.findAll(user); for (FeedSubscription sub : subs) { - Date disabledUntil = sub.getFeed().getDisabledUntil(); - if (disabledUntil == null || disabledUntil.before(new Date())) { + Instant disabledUntil = sub.getFeed().getDisabledUntil(); + if (disabledUntil == null || disabledUntil.isBefore(Instant.now())) { Feed feed = sub.getFeed(); feedRefreshEngine.refreshImmediately(feed); } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/UserService.java b/commafeed-server/src/main/java/com/commafeed/backend/service/UserService.java index f4e1d04a..d7cd1439 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/UserService.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/UserService.java @@ -1,9 +1,9 @@ package com.commafeed.backend.service; +import java.time.Instant; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -130,7 +130,7 @@ public class UserService { byte[] salt = encryptionService.generateSalt(); user.setName(name); user.setEmail(email); - user.setCreated(new Date()); + user.setCreated(Instant.now()); user.setSalt(salt); user.setPassword(encryptionService.getEncryptedPassword(password, salt)); userDAO.saveOrUpdate(user); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/service/internal/PostLoginActivities.java b/commafeed-server/src/main/java/com/commafeed/backend/service/internal/PostLoginActivities.java index 5f554a89..d6231111 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/service/internal/PostLoginActivities.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/service/internal/PostLoginActivities.java @@ -1,8 +1,7 @@ package com.commafeed.backend.service.internal; -import java.util.Date; - -import org.apache.commons.lang3.time.DateUtils; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.dao.UnitOfWork; @@ -25,9 +24,9 @@ public class PostLoginActivities { public void executeFor(User user) { // only update lastLogin every once in a while in order to avoid invalidating the cache every time someone logs in - Date now = new Date(); - Date lastLogin = user.getLastLogin(); - if (lastLogin == null || lastLogin.before(DateUtils.addMinutes(now, -30))) { + Instant now = Instant.now(); + Instant lastLogin = user.getLastLogin(); + if (lastLogin == null || ChronoUnit.MINUTES.between(lastLogin, now) >= 30) { user.setLastLogin(now); boolean heavyLoad = Boolean.TRUE.equals(config.getApplicationSettings().getHeavyLoad()); diff --git a/commafeed-server/src/main/java/com/commafeed/backend/task/OldEntriesCleanupTask.java b/commafeed-server/src/main/java/com/commafeed/backend/task/OldEntriesCleanupTask.java index 963cb610..76328ef3 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/task/OldEntriesCleanupTask.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/task/OldEntriesCleanupTask.java @@ -1,10 +1,9 @@ package com.commafeed.backend.task; -import java.util.Date; +import java.time.Duration; +import java.time.Instant; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.time.DateUtils; - import com.commafeed.CommaFeedConfiguration; import com.commafeed.backend.service.DatabaseCleaningService; @@ -23,7 +22,7 @@ public class OldEntriesCleanupTask extends ScheduledTask { public void run() { int maxAgeDays = config.getApplicationSettings().getMaxEntriesAgeDays(); if (maxAgeDays > 0) { - Date threshold = DateUtils.addDays(new Date(), -1 * maxAgeDays); + Instant threshold = Instant.now().minus(Duration.ofDays(maxAgeDays)); cleaner.cleanEntriesOlderThan(threshold); } } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/task/OldStatusesCleanupTask.java b/commafeed-server/src/main/java/com/commafeed/backend/task/OldStatusesCleanupTask.java index 4edb58a2..82c12de1 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/task/OldStatusesCleanupTask.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/task/OldStatusesCleanupTask.java @@ -1,6 +1,6 @@ package com.commafeed.backend.task; -import java.util.Date; +import java.time.Instant; import java.util.concurrent.TimeUnit; import com.commafeed.CommaFeedConfiguration; @@ -19,7 +19,7 @@ public class OldStatusesCleanupTask extends ScheduledTask { @Override public void run() { - Date threshold = config.getApplicationSettings().getUnreadThreshold(); + Instant threshold = config.getApplicationSettings().getUnreadThreshold(); if (threshold != null) { cleaner.cleanStatusesOlderThan(threshold); } diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/model/Entry.java b/commafeed-server/src/main/java/com/commafeed/frontend/model/Entry.java index c2e65fb2..606dcd4d 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/model/Entry.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/model/Entry.java @@ -1,6 +1,7 @@ package com.commafeed.frontend.model; import java.io.Serializable; +import java.time.Instant; import java.util.Collections; import java.util.Date; import java.util.List; @@ -67,10 +68,10 @@ public class Entry implements Serializable { private Integer mediaThumbnailHeight; @Schema(description = "entry publication date", type = "number", requiredMode = RequiredMode.REQUIRED) - private Date date; + private Instant date; @Schema(description = "entry insertion date in the database", type = "number", requiredMode = RequiredMode.REQUIRED) - private Date insertedDate; + private Instant insertedDate; @Schema(description = "feed id", requiredMode = RequiredMode.REQUIRED) private String feedId; @@ -165,7 +166,7 @@ public class Entry implements Serializable { } entry.setLink(getUrl()); - entry.setPublishedDate(getDate()); + entry.setPublishedDate(getDate() == null ? null : Date.from(getDate())); return entry; } } diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/model/Subscription.java b/commafeed-server/src/main/java/com/commafeed/frontend/model/Subscription.java index ce91bee1..1a022af2 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/model/Subscription.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/model/Subscription.java @@ -1,7 +1,7 @@ package com.commafeed.frontend.model; import java.io.Serializable; -import java.util.Date; +import java.time.Instant; import com.commafeed.backend.feed.FeedUtils; import com.commafeed.backend.model.Feed; @@ -30,10 +30,10 @@ public class Subscription implements Serializable { private int errorCount; @Schema(description = "last time the feed was refreshed", type = "number") - private Date lastRefresh; + private Instant lastRefresh; @Schema(description = "next time the feed refresh is planned, null if refresh is already queued", type = "number") - private Date nextRefresh; + private Instant nextRefresh; @Schema(description = "this subscription's feed url", requiredMode = RequiredMode.REQUIRED) private String feedUrl; @@ -54,13 +54,12 @@ public class Subscription implements Serializable { private int position; @Schema(description = "date of the newest item", type = "number") - private Date newestItemTime; + private Instant newestItemTime; @Schema(description = "JEXL string evaluated on new entries to mark them as read if they do not match") private String filter; public static Subscription build(FeedSubscription subscription, UnreadCount unreadCount) { - Date now = new Date(); FeedCategory category = subscription.getCategory(); Feed feed = subscription.getFeed(); Subscription sub = new Subscription(); @@ -73,7 +72,8 @@ public class Subscription implements Serializable { sub.setFeedLink(feed.getLink()); sub.setIconUrl(FeedUtils.getFaviconUrl(subscription)); sub.setLastRefresh(feed.getLastUpdated()); - sub.setNextRefresh((feed.getDisabledUntil() != null && feed.getDisabledUntil().before(now)) ? null : feed.getDisabledUntil()); + sub.setNextRefresh( + (feed.getDisabledUntil() != null && feed.getDisabledUntil().isBefore(Instant.now())) ? null : feed.getDisabledUntil()); sub.setUnread(unreadCount.getUnreadCount()); sub.setNewestItemTime(unreadCount.getNewestItemTime()); sub.setCategoryId(category == null ? null : String.valueOf(category.getId())); diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/model/UnreadCount.java b/commafeed-server/src/main/java/com/commafeed/frontend/model/UnreadCount.java index 94d743c7..4f946ea2 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/model/UnreadCount.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/model/UnreadCount.java @@ -1,7 +1,7 @@ package com.commafeed.frontend.model; import java.io.Serializable; -import java.util.Date; +import java.time.Instant; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -18,12 +18,12 @@ public class UnreadCount implements Serializable { private long unreadCount; @Schema(type = "number") - private Date newestItemTime; + private Instant newestItemTime; public UnreadCount() { } - public UnreadCount(long feedId, long unreadCount, Date newestItemTime) { + public UnreadCount(long feedId, long unreadCount, Instant newestItemTime) { this.feedId = feedId; this.unreadCount = unreadCount; this.newestItemTime = newestItemTime; diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/model/UserModel.java b/commafeed-server/src/main/java/com/commafeed/frontend/model/UserModel.java index 4bf4a3d7..7c7d332a 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/model/UserModel.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/model/UserModel.java @@ -1,7 +1,7 @@ package com.commafeed.frontend.model; import java.io.Serializable; -import java.util.Date; +import java.time.Instant; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; @@ -31,10 +31,10 @@ public class UserModel implements Serializable { private boolean enabled; @Schema(description = "account creation date", type = "number") - private Date created; + private Instant created; @Schema(description = "last login date", type = "number") - private Date lastLogin; + private Instant lastLogin; @Schema(description = "user is admin", requiredMode = RequiredMode.REQUIRED) private boolean admin; diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/CategoryREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/CategoryREST.java index c42fb60f..b9868ef8 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/CategoryREST.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/CategoryREST.java @@ -1,9 +1,9 @@ package com.commafeed.frontend.resource; import java.io.StringWriter; +import java.time.Instant; import java.util.Arrays; import java.util.Comparator; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; @@ -131,7 +131,7 @@ public class CategoryREST { id = ALL; } - Date newerThanDate = newerThan == null ? null : new Date(newerThan); + Instant newerThanDate = newerThan == null ? null : Instant.ofEpochMilli(newerThan); List excludedIds = null; if (StringUtils.isNotEmpty(excludedSubscriptionIds)) { @@ -242,8 +242,8 @@ public class CategoryREST { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); - Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan()); - Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore()); + Instant olderThan = req.getOlderThan() == null ? null : Instant.ofEpochMilli(req.getOlderThan()); + Instant insertedBefore = req.getInsertedBefore() == null ? null : Instant.ofEpochMilli(req.getInsertedBefore()); String keywords = req.getKeywords(); List entryKeywords = FeedEntryKeyword.fromQueryString(keywords); diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/FeedREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/FeedREST.java index 8d91f2d5..5f758aa0 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/FeedREST.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/FeedREST.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.StringWriter; import java.net.URI; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -164,7 +165,7 @@ public class FeedREST { boolean unreadOnly = readType == ReadingMode.unread; - Date newerThanDate = newerThan == null ? null : new Date(newerThan); + Instant newerThanDate = newerThan == null ? null : Instant.ofEpochMilli(newerThan); FeedSubscription subscription = feedSubscriptionDAO.findById(user, Long.valueOf(id)); if (subscription != null) { @@ -321,8 +322,8 @@ public class FeedREST { Preconditions.checkNotNull(req); Preconditions.checkNotNull(req.getId()); - Date olderThan = req.getOlderThan() == null ? null : new Date(req.getOlderThan()); - Date insertedBefore = req.getInsertedBefore() == null ? null : new Date(req.getInsertedBefore()); + Instant olderThan = req.getOlderThan() == null ? null : Instant.ofEpochMilli(req.getOlderThan()); + Instant insertedBefore = req.getInsertedBefore() == null ? null : Instant.ofEpochMilli(req.getInsertedBefore()); String keywords = req.getKeywords(); List entryKeywords = FeedEntryKeyword.fromQueryString(keywords); @@ -379,7 +380,7 @@ public class FeedREST { Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MONTH, 1); builder.expires(calendar.getTime()); - builder.lastModified(CommaFeedApplication.STARTUP_TIME); + builder.lastModified(Date.from(CommaFeedApplication.STARTUP_TIME)); return builder.build(); } diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java index 335a52d1..a8452bf5 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/UserREST.java @@ -1,14 +1,14 @@ package com.commafeed.frontend.resource; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Collections; -import java.util.Date; import java.util.Optional; import java.util.UUID; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.time.DateUtils; import org.apache.hc.core5.net.URIBuilder; import com.codahale.metrics.annotation.Timed; @@ -282,7 +282,7 @@ public class UserREST { try { user.setRecoverPasswordToken(DigestUtils.sha1Hex(UUID.randomUUID().toString())); - user.setRecoverPasswordTokenDate(new Date()); + user.setRecoverPasswordTokenDate(Instant.now()); userDAO.saveOrUpdate(user); mailService.sendMail(user, "Password recovery", buildEmailContent(user)); return Response.ok().build(); @@ -325,7 +325,7 @@ public class UserREST { if (user.getRecoverPasswordToken() == null || !user.getRecoverPasswordToken().equals(token)) { return Response.status(Status.UNAUTHORIZED).entity("Invalid token.").build(); } - if (user.getRecoverPasswordTokenDate().before(DateUtils.addDays(new Date(), -2))) { + if (ChronoUnit.DAYS.between(user.getRecoverPasswordTokenDate(), Instant.now()) >= 2) { return Response.status(Status.UNAUTHORIZED).entity("token expired.").build(); } diff --git a/commafeed-server/src/main/java/com/commafeed/frontend/resource/fever/FeverREST.java b/commafeed-server/src/main/java/com/commafeed/frontend/resource/fever/FeverREST.java index 622fa70a..cedb914b 100644 --- a/commafeed-server/src/main/java/com/commafeed/frontend/resource/fever/FeverREST.java +++ b/commafeed-server/src/main/java/com/commafeed/frontend/resource/fever/FeverREST.java @@ -5,7 +5,6 @@ import java.util.ArrayList; import java.util.Base64; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -189,7 +188,7 @@ public class FeverREST { if (params.containsKey("mark") && params.containsKey("id") && params.containsKey("as")) { long id = Long.parseLong(params.get("id")); String before = params.get("before"); - Date insertedBefore = before == null ? null : Date.from(Instant.ofEpochSecond(Long.parseLong(before))); + Instant insertedBefore = before == null ? null : Instant.ofEpochSecond(Long.parseLong(before)); mark(user, params.get("mark"), id, params.get("as"), insertedBefore); } @@ -206,7 +205,7 @@ public class FeverREST { .map(Feed::getLastUpdated) .filter(Objects::nonNull) .max(Comparator.naturalOrder()) - .map(d -> d.toInstant().getEpochSecond()) + .map(d -> d.getEpochSecond()) .orElse(0L); } @@ -242,7 +241,7 @@ public class FeverREST { f.setUrl(s.getFeed().getUrl()); f.setSiteUrl(s.getFeed().getLink()); f.setSpark(false); - f.setLastUpdatedOnTime(s.getFeed().getLastUpdated() == null ? 0 : s.getFeed().getLastUpdated().toInstant().getEpochSecond()); + f.setLastUpdatedOnTime(s.getFeed().getLastUpdated() == null ? 0 : s.getFeed().getLastUpdated().getEpochSecond()); return f; }).toList(); } @@ -291,7 +290,7 @@ public class FeverREST { i.setUrl(s.getEntry().getUrl()); i.setSaved(s.isStarred()); i.setRead(s.isRead()); - i.setCreatedOnTime(s.getEntryUpdated().toInstant().getEpochSecond()); + i.setCreatedOnTime(s.getEntryUpdated().getEpochSecond()); return i; } @@ -306,7 +305,7 @@ public class FeverREST { }).toList(); } - private void mark(User user, String source, long id, String action, Date insertedBefore) { + private void mark(User user, String source, long id, String action, Instant insertedBefore) { if ("item".equals(source)) { if ("read".equals(action) || "unread".equals(action)) { feedEntryService.markEntry(user, id, "read".equals(action)); diff --git a/commafeed-server/src/test/java/com/commafeed/backend/feed/FeedFetcherTest.java b/commafeed-server/src/test/java/com/commafeed/backend/feed/FeedFetcherTest.java index fcec5b41..24cafbf3 100644 --- a/commafeed-server/src/test/java/com/commafeed/backend/feed/FeedFetcherTest.java +++ b/commafeed-server/src/test/java/com/commafeed/backend/feed/FeedFetcherTest.java @@ -1,6 +1,6 @@ package com.commafeed.backend.feed; -import java.util.Date; +import java.time.Instant; import java.util.Set; import org.apache.commons.codec.digest.DigestUtils; @@ -49,7 +49,7 @@ class FeedFetcherTest { .thenReturn(new HttpResult(content, "content-type", "last-modified-2", "etag-2", 20, null)); NotModifiedException e = Assertions.assertThrows(NotModifiedException.class, - () -> fetcher.fetch(url, false, lastModified, etag, new Date(), lastContentHash)); + () -> fetcher.fetch(url, false, lastModified, etag, Instant.now(), lastContentHash)); Assertions.assertEquals("last-modified-2", e.getNewLastModifiedHeader()); Assertions.assertEquals("etag-2", e.getNewEtagHeader()); diff --git a/commafeed-server/src/test/java/com/commafeed/e2e/PlaywrightTestBase.java b/commafeed-server/src/test/java/com/commafeed/e2e/PlaywrightTestBase.java index ae157c65..eb2acdd4 100644 --- a/commafeed-server/src/test/java/com/commafeed/e2e/PlaywrightTestBase.java +++ b/commafeed-server/src/test/java/com/commafeed/e2e/PlaywrightTestBase.java @@ -3,8 +3,8 @@ package com.commafeed.e2e; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.Optional; import org.junit.jupiter.api.AfterAll; @@ -115,7 +115,7 @@ public class PlaywrightTestBase { private String getFileName(ExtensionContext context) { return String.format("%s.%s-%s", context.getRequiredTestClass().getSimpleName(), context.getRequiredTestMethod().getName(), - new SimpleDateFormat("yyyy-MM-dd--HH-mm-ss").format(new Date())); + DateTimeFormatter.ofPattern("yyyy-MM-dd--HH-mm-ss").format(Instant.now())); } private void saveScreenshot(PlaywrightTestBase testInstance, String fileName) { diff --git a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java index 7807e6c8..b788f151 100644 --- a/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java +++ b/commafeed-server/src/test/java/com/commafeed/integration/rest/FeedIT.java @@ -3,9 +3,9 @@ package com.commafeed.integration.rest; import java.io.IOException; import java.io.InputStream; import java.time.Duration; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.Objects; import org.apache.commons.io.IOUtils; @@ -99,13 +99,13 @@ class FeedIT extends BaseIT { @Test void markOlderThan() { long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); - markFeedEntries(subscriptionId, new GregorianCalendar(2023, Calendar.DECEMBER, 28).getTime(), null); + markFeedEntries(subscriptionId, LocalDate.of(2023, 12, 28).atStartOfDay().toInstant(ZoneOffset.UTC), null); Assertions.assertEquals(1, getFeedEntries(subscriptionId).getEntries().stream().filter(Entry::isRead).count()); } @Test void markInsertedBeforeBeforeSubscription() { - Date insertedBefore = new Date(); + Instant insertedBefore = Instant.now(); long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); markFeedEntries(subscriptionId, null, insertedBefore); @@ -116,17 +116,17 @@ class FeedIT extends BaseIT { void markInsertedBeforeAfterSubscription() { long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); - Date insertedBefore = new Date(); + Instant insertedBefore = Instant.now(); markFeedEntries(subscriptionId, null, insertedBefore); Assertions.assertTrue(getFeedEntries(subscriptionId).getEntries().stream().allMatch(Entry::isRead)); } - private void markFeedEntries(long subscriptionId, Date olderThan, Date insertedBefore) { + private void markFeedEntries(long subscriptionId, Instant olderThan, Instant insertedBefore) { MarkRequest request = new MarkRequest(); request.setId(String.valueOf(subscriptionId)); - request.setOlderThan(olderThan == null ? null : olderThan.getTime()); - request.setInsertedBefore(insertedBefore == null ? null : insertedBefore.getTime()); + request.setOlderThan(olderThan == null ? null : olderThan.toEpochMilli()); + request.setInsertedBefore(insertedBefore == null ? null : insertedBefore.toEpochMilli()); getClient().target(getApiBaseUrl() + "feed/mark").request().post(Entity.json(request), Void.TYPE); } } @@ -137,26 +137,26 @@ class FeedIT extends BaseIT { void refresh() { Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); - Date now = new Date(); + Instant now = Instant.now(); IDRequest request = new IDRequest(); request.setId(subscriptionId); getClient().target(getApiBaseUrl() + "feed/refresh").request().post(Entity.json(request), Void.TYPE); Awaitility.await() .atMost(Duration.ofSeconds(15)) - .until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().after(now)); + .until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().isAfter(now)); } @Test void refreshAll() { Long subscriptionId = subscribeAndWaitForEntries(getFeedUrl()); - Date now = new Date(); + Instant now = Instant.now(); getClient().target(getApiBaseUrl() + "feed/refreshAll").request().get(Void.TYPE); Awaitility.await() .atMost(Duration.ofSeconds(15)) - .until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().after(now)); + .until(() -> getSubscription(subscriptionId), f -> f.getLastRefresh().isAfter(now)); } }