Added experimental about page, updated more Rome code, first preparations to adapt feed fetcher code

This commit is contained in:
2024-02-12 17:41:04 +01:00
parent 3a23ac4503
commit 87f05e6894
22 changed files with 1700 additions and 1484 deletions

View File

@@ -1,18 +1,220 @@
package dev.rsems.feedreader;
import com.rometools.fetcher.FeedFetcher;
import com.rometools.fetcher.impl.FeedFetcherCache;
import com.rometools.fetcher.impl.HttpURLFeedFetcher;
import com.rometools.fetcher.impl.LinkedHashMapFeedInfoCache;
import dev.rsems.feedreader.fetcher.FetcherEventListenerImpl;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@Controller @Slf4j
public class FeedReaderController {
@Value("${spring.application.name}")
String appName;
private static final Logger logger = log;
private static final FeedFetcherCache feedInfoCache = LinkedHashMapFeedInfoCache.getInstance();
public static final FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache);
private static final FetcherEventListenerImpl listener = new FetcherEventListenerImpl();
static {
fetcher.addFetcherEventListener(listener);
}
private static final int MAX_ITEMS_PER_FEED = 20;
private static final DateFormat TIME_FMT = new SimpleDateFormat("HH:mm");
private static final DateFormat DAY_FMT = new SimpleDateFormat("EEEE',' dd. M. yyyy");
@GetMapping("/")
public String homePage(Model model) {
public String index(Model model) {
model.addAttribute("appName", appName);
// Stopwatch stw = new Stopwatch(true);
//
// Set<FeedFetcherTask> feedFetcherTasks = new TreeSet<FeedFetcherTask>();
//
// logger.info("[" + "] Reading database and building the feed fetcher tasks list");
//
// ConnectionSource connectionSource = null;
// try {
// connectionSource = new JdbcConnectionSource("jdbc:mysql://db.rsems.de/feeds?user=feeds&password=fems1211");
// Dao<UserFeed, Integer> userFeedDao = DaoManager.createDao(connectionSource, UserFeed.class);
// CloseableIterator<UserFeed> ituf = userFeedDao.closeableIterator();
// try {
// int i = 0;
// while (ituf.hasNext()) {
// UserFeed userFeed = ituf.next();
// if (userFeed.getVisible()) {
// i++;
//
// feedFetcherTasks.add(new FeedFetcherTask(i, userFeed.getFeed().getName(), userFeed.getFeed().getUrl(), "", userFeed.getFilter()));
// // logger.info("[" + remoteHost + "] #" + new DecimalFormat("00").format(i) + " " + userFeed.getFeed().getName() + " added");
// }
// }
// } catch (Exception e) {
// logger.error(ExceptionUtils.getMessages(e));
// logger.error("\n" + ExceptionUtils.getStackTrace(e));
// throw new FeedException(e);
// } finally {
// ituf.close();
// }
// } catch (SQLException e) {
// logger.error(ExceptionUtils.getMessages(e));
// logger.error("\n" + ExceptionUtils.getStackTrace(e));
// throw new FeedException("Failed to access database", e);
// } finally {
// if (connectionSource != null) {
// try {
// connectionSource.close();
// } catch (SQLException unhandled) {
// }
// }
// }
//
// logger.info("[" + remoteHost + "] About to invoke " + feedFetcherTasks.size() + " feed retrieval tasks after "
// + stw.getTimeElapsed() + " ms");
//
// List<Future<IFeed>> feedFutures = null;
// ExecutorService executorService = Executors.newCachedThreadPool();
// try {
// feedFutures = executorService.invokeAll(feedFetcherTasks);
// } catch (InterruptedException e) {
// logger.error(ExceptionUtils.getMessages(e));
// logger.error("\n" + ExceptionUtils.getStackTrace(e));
// throw new FeedException(e);
// }
//
// logger.info("[" + remoteHost + "] About to extract retrieved data from task results after " + stw.getTimeElapsed() + " ms");
//
// ArrayList<IFeed> feeds = new ArrayList<IFeed>();
// try {
// for (Future<IFeed> ff : feedFutures) {
// feeds.add(ff.get());
// }
// } catch (Exception e) {
// logger.error(ExceptionUtils.getMessages(e));
// logger.error("\n" + ExceptionUtils.getStackTrace(e));
// throw new FeedException(e);
// } finally {
// executorService.shutdown();
// }
//
// logger.info("[" + remoteHost + "] About to render retrieved data after " + stw.getTimeElapsed() + " ms");
//
// add(new Label("head.title", Globals.TITLE));
// RepeatingView feedRv = new RepeatingView("feed");
// add(feedRv);
//
// int fc = 0;
// for (IFeed feed : feeds) {
// fc++;
//
// long lap = stw.getTimeElapsed();
//
// WebMarkupContainer feedMarkup = new WebMarkupContainer(feedRv.newChildId());
// feedRv.add(feedMarkup);
// String errorStatus = feed.getErrorStatus();
//
// feedMarkup.add(new ExternalLink("feedtitle", (feed.getLink() == null ? "" : feed.getLink()), feed.getName()));
//
// if (errorStatus.equals("")) {
// feedMarkup.add(new ExternalLink("feedurl", feed.getUrl().toExternalForm(), feed.getTitle()));
// feedMarkup
// .add(new Label("feeddate", feed.getDate() != null ? Globals.DEFAULT_DISPLAY_DATE_FORMAT.format(feed.getDate()) : " ")); // this is ANSI 160, not space
// } else {
// feedMarkup.add(new ExternalLink("feedurl", feed.getUrl().toExternalForm(), "Error retrieving feed").add(new Behavior() {
// @Override
// public void beforeRender(Component component) {
// component.getResponse().write("<strong>");
// super.beforeRender(component);
// }
//
// @Override
// public void afterRender(Component component) {
// super.afterRender(component);
// component.getResponse().write("</strong>");
// }
// }));
// feedMarkup.add(new Label("feeddate", errorStatus));
// }
//
// RepeatingView itemRv = new RepeatingView("item");
// feedMarkup.add(itemRv);
// String lastDay = null;
// ArrayList<FeedItem> items = feed.getFeedItems();
//
// if (feed.getErrorStatus() != "") {
// logger.info("[Client " + remoteHost + "] " + feed.getErrorStatus() + "\n" + feed.getStackTrace());
// }
//
// Collections.sort(items, FeedItem.LATEST_FIRST);
// int count = 0;
// for (Iterator<FeedItem> it = items.iterator(); it.hasNext(); ) {
// FeedItem item = it.next();
//
// String itemlabel = item.getTitle() == null ? "—" : StringUtils.cleanHtml(item.getTitle(), feed.getUrl().getPath());
//
// if (!item.getTitle().isEmpty() && !feed.getFilter().matches(itemlabel)) {
//
// WebMarkupContainer itemMarkup = new WebMarkupContainer(itemRv.newChildId());
// itemRv.add(itemMarkup);
//
// Date itemDate = item.getDate();
// String day = itemDate == null ? " " : DAY_FMT.format(itemDate); // &#160; not space
// final boolean dayEqualsLastDay = day.equals(lastDay);
// itemMarkup.add(new Label("date", day) {
// @Override
// public boolean isVisible() {
// return !dayEqualsLastDay;
// }
// });
// if (!dayEqualsLastDay) {
// lastDay = day;
// }
// itemMarkup.add(new Label("itemdate", itemDate == null ? "—" : TIME_FMT.format(itemDate)));
//
// String itemlink = item.getLink() == null ? "" : item.getLink();
//
// String itemsummary = item.getSummary() == null ? "" : StringUtils.cleanHtml(item.getSummary(), feed.getUrl().getPath());
// itemMarkup.add(new ExternalLink("itemlink", itemlink, itemlabel).add(new AttributeModifier("title", itemsummary)));
//
// String itemAuthor = item.getAuthor() == null || item.getAuthor().equals("") ? ""
// : " (" + item.getAuthor().replaceFirst("(.*?)<(.*?)@(.*?)>", "$1").trim() + ")";
// itemMarkup.add(new Label("itemauthor", StringUtils.unquote(itemAuthor)));
//
// count++;
// if (count >= MAX_ITEMS_PER_FEED) {
// break;
// }
//
// }
//
// }
//
// logger.info("[" + remoteHost + "] #" + fc + ": " + count + " feed items processed (" + (stw.getTimeElapsed() - lap) + " ms)");
//
// }
//
// add(new Label("foot", Globals.TITLE + " " + Version.VERSION + " " + Globals.DEFAULT_DISPLAY_DATE_FORMAT.format(new Date())));
//
// logger.info("[" + remoteHost + "] Finished processing feeds after " + stw.getTimeElapsed() + " ms");
return "index";
}
@GetMapping("/about")
public String about(Model model) {
model.addAttribute("appName", appName);
return "about";
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.io.impl.PropertiesLoader;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.rss.Channel;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.rss.*;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.rss.*;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.rss.Item;
import org.jdom2.Element;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.rss.Channel;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.rss.Channel;

View File

@@ -1,4 +1,4 @@
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
/*
* Copyright 2004 Sun Microsystems, Inc.

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*
*/
package dev.rsems.syndication.rome.io.impl;
package dev.rsems.rometools.rome.io.impl;
import com.rometools.rome.feed.WireFeed;
import org.jdom2.Document;

View File

@@ -1,13 +1,13 @@
# Feed Parser implementation classes
#
WireFeedParser.classes=dev.rsems.syndication.rome.io.impl.RSS090Parser \
com.sun.syndication.io.impl.RSS091NetscapeParser \
com.sun.syndication.io.impl.RSS091UserlandParser \
com.sun.syndication.io.impl.RSS092Parser \
dev.rsems.syndication.rome.io.impl.RSS093Parser \
dev.rsems.syndication.rome.io.impl.RSS094Parser \
dev.rsems.syndication.rome.io.impl.RSS10Parser \
dev.rsems.syndication.rome.io.impl.RSS20wNSParser \
dev.rsems.syndication.rome.io.impl.RSS20Parser \
com.sun.syndication.io.impl.Atom10Parser \
com.sun.syndication.io.impl.Atom03Parser
WireFeedParser.classes=dev.rsems.rometools.rome.io.impl.RSS090Parser \
com.rometools.rome.io.impl.RSS091NetscapeParser \
com.rometools.rome.io.impl.RSS091UserlandParser \
com.rometools.rome.io.impl.RSS092Parser \
dev.rsems.rometools.rome.io.impl.RSS093Parser \
dev.rsems.rometools.rome.io.impl.RSS094Parser \
dev.rsems.rometools.rome.io.impl.RSS10Parser \
dev.rsems.rometools.rome.io.impl.RSS20wNSParser \
dev.rsems.rometools.rome.io.impl.RSS20Parser \
com.rometools.rome.io.impl.Atom10Parser \
com.rometools.rome.io.impl.Atom03Parser

View File

@@ -0,0 +1,13 @@
<html lang="en">
<head>
<title th:text="'About ' + ${appName}"></title>
<link th:href="@{/styles/stylesheet.css}" rel="stylesheet" />
<link th:href="@{/favicon.ico}" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<h1>About <a href="/" th:text="${appName}"></a></h1>
<p>This is a feed aggregator &amp; feed reader application</p>
<hr />
<div class="foot" th:text="${appName}"></div>
</body>
</html>

View File

@@ -5,6 +5,7 @@
<link th:href="@{/favicon.ico}" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<h1 th:text="${appName}"></h1><h2><a href="/about">About</a></h2>
<div class="page">
<div class="feeds">
<div class="feed">