diff --git a/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java b/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java index bc792e4..725e67e 100644 --- a/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java +++ b/src/main/java/com/apptasticsoftware/rssreader/AbstractRssReader.java @@ -33,9 +33,7 @@ import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.lang.ref.Cleaner; import java.net.URI; import java.net.http.HttpClient; @@ -403,8 +401,8 @@ public AbstractRssReader addChannelExtension(String tag, String attribute, } /** - * Read RSS feed with the given URL. - * @param url URL to RSS feed. + * Read RSS feed with the given URL or file URI. + * @param url URL to RSS feed or file URI. * @return Stream of items * @throws IOException Fail to read url or its content */ @@ -432,11 +430,12 @@ public Stream read(String url) throws IOException { /** * Read from a collections of RSS feed. - * @param urls collections of URLs + * @param urls collections of URLs or file URIs * @return Stream of items */ public Stream read(Collection urls) { Objects.requireNonNull(urls, "URLs collection must not be null"); + urls.forEach(url -> Objects.requireNonNull(url, "URL must not be null. Url: " + url)); if (!isInitialized) { initialize(); @@ -498,7 +497,19 @@ public CompletableFuture> readAsync(String url) { initialize(); isInitialized = true; } - return sendAsyncRequest(url).thenApply(processResponse()); + + var uri = URI.create(url); + if ("file".equals(uri.getScheme())) { + return CompletableFuture.supplyAsync(() -> { + try { + return read(new FileInputStream(uri.getPath())); + } catch (FileNotFoundException e) { + throw new CompletionException(e); + } + }); + } else { + return sendAsyncRequest(url).thenApply(processResponse()); + } } /** diff --git a/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java b/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java index af190db..4b44783 100644 --- a/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java +++ b/src/test/java/com/apptasticsoftware/integrationtest/RssReaderIntegrationTest.java @@ -821,7 +821,39 @@ void atomFeedWithCategory() { assertEquals("Azure", list.get(2).getCategories().get(2)); } + @Test + void readFromFileUri() throws IOException, URISyntaxException { + var uri = getFileUri("rss-feed.xml"); + var items = new RssReader().read(uri).collect(Collectors.toList()); + assertEquals(20, items.size()); + } + + @Test + void readFromMultipleFileUri() throws URISyntaxException { + var uris = List.of( + getFileUri("rss-feed.xml"), + getFileUri("atom-feed.xml") + ); + var items = new RssReader().read(uris).collect(Collectors.toList()); + assertEquals(23, items.size()); + } + + @Test + void readFromAMixOfUrlAndFileUri() throws URISyntaxException { + var sources = List.of( + getFileUri("rss-feed.xml"), + "https://www.nasa.gov/news-release/feed/", + getFileUri("atom-feed.xml") + ); + var items = new RssReader().read(sources).collect(Collectors.toList()); + assertEquals(33, items.size()); + } + private InputStream fromFile(String fileName) { return getClass().getClassLoader().getResourceAsStream(fileName); } + + private String getFileUri(String fileName) throws URISyntaxException { + return getClass().getClassLoader().getResource(fileName).toURI().toString(); + } } diff --git a/src/test/java/com/apptasticsoftware/integrationtest/SortTest.java b/src/test/java/com/apptasticsoftware/integrationtest/SortTest.java index 3df5734..a102399 100644 --- a/src/test/java/com/apptasticsoftware/integrationtest/SortTest.java +++ b/src/test/java/com/apptasticsoftware/integrationtest/SortTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -46,10 +45,7 @@ void testTimestampSortTest() { "https://feeds.arstechnica.com/arstechnica/science" ); - List extendedUrlList = new ArrayList<>(urlList); - extendedUrlList.add(null); - - var timestamps = new RssReader().read(extendedUrlList) + var timestamps = new RssReader().read(urlList) .sorted() .map(Item::getPubDateZonedDateTime) .flatMap(Optional::stream)