-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from Eukon05/spring
Added a REST API built with Spring Boot
- Loading branch information
Showing
18 changed files
with
263 additions
and
51 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,4 +10,6 @@ default List<Article> getLatest() { | |
} | ||
|
||
List<Article> getLatest(int limit); | ||
|
||
ArticleSourceInfo getSourceInfo(); | ||
} |
4 changes: 4 additions & 0 deletions
4
infodb-api-source/src/main/java/ovh/eukon05/infodb/api/source/ArticleSourceInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package ovh.eukon05.infodb.api.source; | ||
|
||
public record ArticleSourceInfo(String name, String url) { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,16 @@ | ||
import ovh.eukon05.infodb.api.persistence.ArticleDAO; | ||
import ovh.eukon05.infodb.api.source.ArticleSource; | ||
|
||
module ovh.eukon05.infodb.app { | ||
open module ovh.eukon05.infodb.app { | ||
requires ovh.eukon05.infodb.api.source; | ||
requires ovh.eukon05.infodb.api.persistence; | ||
requires spring.boot; | ||
requires spring.boot.autoconfigure; | ||
requires spring.context; | ||
requires jakarta.persistence; | ||
requires org.slf4j; | ||
requires spring.web; | ||
requires io.swagger.v3.oas.annotations; | ||
uses ArticleSource; | ||
uses ArticleDAO; | ||
} |
36 changes: 36 additions & 0 deletions
36
infodb-app/src/main/java/ovh/eukon05/infodb/app/ArticlesController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package ovh.eukon05.infodb.app; | ||
|
||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import org.springframework.web.bind.annotation.*; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDAO; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDTO; | ||
import ovh.eukon05.infodb.api.persistence.ArticleSearchCriteria; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/articles") | ||
@CrossOrigin(origins = {"http://localhost:3000", "http://127.0.0.1:3000"}) | ||
@Tag(name = "Articles", description = "API methods related to fetching article data collected by infodb") | ||
class ArticlesController { | ||
private final ArticleDAO dao; | ||
|
||
public ArticlesController(List<ArticleDAO> daos) { | ||
dao = daos.get(0); | ||
} | ||
|
||
@GetMapping("/latest") | ||
public List<ArticleDTO> getLatest(@RequestParam(required = false, defaultValue = "0") int page) { | ||
return dao.getLatest(page); | ||
} | ||
|
||
@PostMapping | ||
public List<ArticleDTO> search(@RequestParam(required = false, defaultValue = "0") int page, @RequestBody ArticleSearchCriteria criteria) { | ||
return dao.findByCriteria(criteria, page); | ||
} | ||
|
||
@GetMapping("/{id}") | ||
public ArticleDTO getById(@PathVariable String id) { | ||
return dao.findById(id); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
infodb-app/src/main/java/ovh/eukon05/infodb/app/BeanConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package ovh.eukon05.infodb.app; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDAO; | ||
import ovh.eukon05.infodb.api.source.ArticleSource; | ||
import ovh.eukon05.infodb.api.source.ArticleSourceInfo; | ||
|
||
import java.util.List; | ||
import java.util.ServiceLoader; | ||
|
||
@Configuration | ||
class BeanConfig { | ||
|
||
@Bean | ||
List<ArticleDAO> articleDAOs() { | ||
ServiceLoader<ArticleDAO> loader = ServiceLoader.load(ArticleDAO.class); | ||
|
||
if (!loader.iterator().hasNext()) { | ||
throw new IllegalStateException("No ArticleDAO found"); | ||
} | ||
|
||
return loader.stream().map(ServiceLoader.Provider::get).toList(); | ||
} | ||
|
||
@Bean | ||
List<ArticleSource> articleSources() { | ||
ServiceLoader<ArticleSource> loader = ServiceLoader.load(ArticleSource.class); | ||
|
||
if (!loader.iterator().hasNext()) { | ||
throw new IllegalStateException("No ArticleSource found"); | ||
} | ||
|
||
return loader.stream().map(ServiceLoader.Provider::get).toList(); | ||
} | ||
|
||
@Bean | ||
List<ArticleSourceInfo> articleSourceInfos() { | ||
return articleSources().stream().map(ArticleSource::getSourceInfo).toList(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,16 @@ | ||
package ovh.eukon05.infodb.app; | ||
|
||
import ovh.eukon05.infodb.api.persistence.ArticleDAO; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDTO; | ||
import ovh.eukon05.infodb.api.persistence.ArticleSearchCriteria; | ||
import ovh.eukon05.infodb.api.source.ArticleSource; | ||
|
||
import java.time.Instant; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.Collections; | ||
import java.util.ServiceLoader; | ||
import io.swagger.v3.oas.annotations.OpenAPIDefinition; | ||
import io.swagger.v3.oas.annotations.info.Info; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
import org.springframework.scheduling.annotation.EnableScheduling; | ||
|
||
@SpringBootApplication | ||
@EnableScheduling | ||
@OpenAPIDefinition(info = @Info(title = "infodb", description = "A REST API exposing articles regularly collected from multiple news sources", version = "v1")) | ||
public class Main { | ||
public static void main(String[] args) { | ||
ServiceLoader<ArticleSource> sources = ServiceLoader.load(ArticleSource.class); | ||
ArticleDAO dao = null; | ||
|
||
for (ArticleDAO d : ServiceLoader.load(ArticleDAO.class)) { | ||
if (d.getClass().getName().contains("Hibernate")) { | ||
dao = d; | ||
break; | ||
} | ||
} | ||
|
||
for (ArticleSource source : sources) { | ||
source.getLatest(20).stream() | ||
.map(e -> new ArticleDTO(e.id(), e.origin(), e.title(), e.url(), e.imageUrl(), e.datePublished(), e.tags())) | ||
.forEach(dao::save); | ||
} | ||
|
||
ArticleSearchCriteria criteria = new ArticleSearchCriteria(null, null, Instant.now().minus(2, ChronoUnit.HOURS), Instant.now().minus(30, ChronoUnit.MINUTES), Collections.emptyList()); | ||
dao.findByCriteria(criteria, 0).forEach(System.out::println); | ||
//dao.getLatest(0).forEach(System.out::println); | ||
SpringApplication.run(Main.class, args); | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
infodb-app/src/main/java/ovh/eukon05/infodb/app/PersistenceScheduler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package ovh.eukon05.infodb.app; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Service; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDAO; | ||
import ovh.eukon05.infodb.api.persistence.ArticleDTO; | ||
import ovh.eukon05.infodb.api.source.Article; | ||
import ovh.eukon05.infodb.api.source.ArticleSource; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
|
||
@Service | ||
class PersistenceScheduler { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceScheduler.class); | ||
private static final Function<Article, ArticleDTO> MAPPER = article -> new ArticleDTO(article.id(), article.origin(), article.title(), article.url(), article.imageUrl(), article.datePublished(), article.tags()); | ||
|
||
private final List<ArticleSource> sources; | ||
private final List<ArticleDAO> daos; | ||
private final Set<String> cache = new HashSet<>(); | ||
|
||
public PersistenceScheduler(List<ArticleSource> sources, List<ArticleDAO> daos) { | ||
this.sources = sources; | ||
this.daos = daos; | ||
} | ||
|
||
@Scheduled(initialDelay = 0, fixedDelay = 300000) | ||
private void fetchAndSave() { | ||
LOGGER.info("Scheduled article fetch started"); | ||
|
||
sources.forEach(source -> { | ||
LOGGER.debug("Fetching articles from source: {}", source.getClass().getSimpleName()); | ||
|
||
for (Article article : source.getLatest()) { | ||
if (cache.contains(article.id())) | ||
continue; | ||
|
||
for (ArticleDAO dao : daos) { | ||
if (dao.findById(article.id()) != null) | ||
break; | ||
|
||
LOGGER.debug("Saving article {} to {}", article, dao.getClass().getSimpleName()); | ||
dao.save(MAPPER.apply(article)); | ||
} | ||
LOGGER.debug("Article {} successfully saved and cached", article.id()); | ||
cache.add(article.id()); | ||
} | ||
}); | ||
|
||
LOGGER.info("Scheduled article fetch finished"); | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
infodb-app/src/main/java/ovh/eukon05/infodb/app/SourcesController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package ovh.eukon05.infodb.app; | ||
|
||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import org.springframework.web.bind.annotation.CrossOrigin; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import ovh.eukon05.infodb.api.source.ArticleSourceInfo; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/api/v1/sources") | ||
@CrossOrigin(origins = {"http://localhost:3000", "http://127.0.0.1:3000"}) | ||
@Tag(name = "Sources", description = "API methods exposing details about article sources used by infodb") | ||
class SourcesController { | ||
private final List<ArticleSourceInfo> sourceInfoList; | ||
|
||
public SourcesController(List<ArticleSourceInfo> sourceInfoList) { | ||
this.sourceInfoList = sourceInfoList; | ||
} | ||
|
||
@GetMapping | ||
public List<ArticleSourceInfo> getSources() { | ||
return sourceInfoList; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
logging.level.ovh.eukon05.infodb.app=INFO | ||
springdoc.api-docs.path=/api/v1/api-docs | ||
springdoc.swagger-ui.path=/api/v1/swagger-ui.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.