Compare commits
2 Commits
01d54a3075
...
023e70469c
Author | SHA1 | Date |
---|---|---|
Michele Artini | 023e70469c | |
Michele Artini | 71e268710a |
12
pom.xml
12
pom.xml
|
@ -21,11 +21,17 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
|
@ -70,6 +76,12 @@
|
||||||
<artifactId>httpclient5</artifactId>
|
<artifactId>httpclient5</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.mail</groupId>
|
||||||
|
<artifactId>mail</artifactId>
|
||||||
|
<version>1.4.7</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|
|
@ -43,6 +43,8 @@ public class MainApplication {
|
||||||
SpringApplication.run(MainApplication.class, args);
|
SpringApplication.run(MainApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Beans for Swagger
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OpenAPI newSwaggerDocket() {
|
public OpenAPI newSwaggerDocket() {
|
||||||
final List<Server> servers = new ArrayList<>();
|
final List<Server> servers = new ArrayList<>();
|
||||||
|
|
|
@ -98,26 +98,26 @@ public class CollectorService {
|
||||||
|
|
||||||
jobExecutor.execute(() -> {
|
jobExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
final LocalDateTime now = LocalDateTime.now();
|
|
||||||
info.setExecutionStatus(ExecutionStatus.RUNNING);
|
info.setExecutionStatus(ExecutionStatus.RUNNING);
|
||||||
oaiCollect(sc, info);
|
oaiCollect(sc, info);
|
||||||
info.setExecutionStatus(ExecutionStatus.COMPLETED);
|
info.setExecutionStatus(ExecutionStatus.COMPLETED);
|
||||||
info.setEnd(now);
|
|
||||||
info.setExpirationDate(now.plusHours(executionDuration));
|
|
||||||
emailSender.notifySuccess(info);
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
info.setExecutionStatus(ExecutionStatus.FAILED);
|
|
||||||
info.setMessage(e.getMessage() + ": " + ExceptionUtils.getStackTrace(e));
|
|
||||||
info.setEnd(LocalDateTime.now());
|
|
||||||
emailSender.notifyFailure(info);
|
|
||||||
} finally {
|
|
||||||
sc.complete();
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(publicBasePath)) {
|
if (StringUtils.isNotBlank(publicBasePath)) {
|
||||||
info.setPublicUrl(publicBasePath + "/" + jobId);
|
info.setPublicUrl(publicBasePath + "/" + jobId);
|
||||||
}
|
}
|
||||||
|
} catch (final Throwable e) {
|
||||||
|
info.setExecutionStatus(ExecutionStatus.FAILED);
|
||||||
|
info.setMessage(e.getMessage() + ": " + ExceptionUtils.getStackTrace(e));
|
||||||
|
} finally {
|
||||||
|
sc.complete();
|
||||||
|
|
||||||
|
final LocalDateTime now = LocalDateTime.now();
|
||||||
|
info.setEnd(now);
|
||||||
|
info.setExpirationDate(now.plusHours(executionDuration));
|
||||||
|
|
||||||
collectionInfoRepository.save(info);
|
collectionInfoRepository.save(info);
|
||||||
|
|
||||||
|
emailSender.sendNotification(info);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ public class CollectorService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void cleanCollectedData(final String storageUrl) throws URISyntaxException {
|
public static void cleanCollectedData(final String storageUrl) throws URISyntaxException {
|
||||||
log.info("[CLEAN] - Deleting: " + storageUrl);
|
log.info("[CLEAN] Deleting expired storage: " + storageUrl);
|
||||||
|
|
||||||
final URI uri = new URI(storageUrl);
|
final URI uri = new URI(storageUrl);
|
||||||
final String protocol = uri.getScheme();
|
final String protocol = uri.getScheme();
|
||||||
|
|
|
@ -1,37 +1,149 @@
|
||||||
package eu.dnetlib.apps.oai.utils;
|
package eu.dnetlib.apps.oai.utils;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import javax.mail.Authenticator;
|
||||||
|
import javax.mail.Message;
|
||||||
|
import javax.mail.PasswordAuthentication;
|
||||||
|
import javax.mail.Session;
|
||||||
|
import javax.mail.Transport;
|
||||||
|
import javax.mail.internet.InternetAddress;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.thymeleaf.TemplateEngine;
|
||||||
|
import org.thymeleaf.context.Context;
|
||||||
|
|
||||||
import eu.dnetlib.apps.oai.model.CollectionInfo;
|
import eu.dnetlib.apps.oai.model.CollectionInfo;
|
||||||
|
import eu.dnetlib.apps.oai.model.ExecutionStatus;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class EmailSender {
|
public class EmailSender {
|
||||||
|
|
||||||
public void notifySuccess(final CollectionInfo info) {
|
private static final Log log = LogFactory.getLog(EmailSender.class);
|
||||||
|
|
||||||
|
private final BlockingQueue<Message> queue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
@Value("${swagger.public_url}")
|
||||||
|
private String publicUrl;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.sender.name}")
|
||||||
|
private String fromName;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.sender.email}")
|
||||||
|
private String fromEmail;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.smtp.host}")
|
||||||
|
private String smtpHost;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.smtp.host}")
|
||||||
|
private long smtpPort;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.smtp.user}")
|
||||||
|
private String smtpUser;
|
||||||
|
|
||||||
|
@Value("${oai.conf.notification.smtp.password}")
|
||||||
|
private String smtpPassword;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TemplateEngine templateEngine;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
final Message message = this.queue.take();
|
||||||
|
if (message != null) {
|
||||||
|
try {
|
||||||
|
log.info("Sending mail...");
|
||||||
|
|
||||||
|
log.info(message.getContent());
|
||||||
|
|
||||||
|
Transport.send(message);
|
||||||
|
|
||||||
|
log.info("...sent");
|
||||||
|
} catch (final Throwable e) {
|
||||||
|
log.error("Error sending email", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e1) {
|
||||||
|
throw new RuntimeException(e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendNotification(final CollectionInfo info) {
|
||||||
if (StringUtils.isNotBlank(info.getNotificationEmail())) {
|
if (StringUtils.isNotBlank(info.getNotificationEmail())) {
|
||||||
sendMail(info.getNotificationEmail(), "OAI Harvesting completed", prepareSuccessMessage(info));
|
final String to = info.getNotificationEmail();
|
||||||
|
if (info.getExecutionStatus() == ExecutionStatus.COMPLETED) {
|
||||||
|
sendMail(to, "OAI Harvesting completed", prepareMessage("success", info));
|
||||||
|
} else {
|
||||||
|
sendMail(to, "OAI Harvesting completed", prepareMessage("failure", info));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyFailure(final CollectionInfo info) {
|
private String prepareMessage(final String template, final CollectionInfo info) {
|
||||||
if (StringUtils.isNotBlank(info.getNotificationEmail())) {
|
final Context context = new Context();
|
||||||
sendMail(info.getNotificationEmail(), "OAI Harvesting completed", prepareFailureMessage(info));
|
context.setVariable("info", info);
|
||||||
|
context.setVariable("baseUrl", publicUrl);
|
||||||
|
return templateEngine.process(template, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMail(final String to, final String subject, final String message) {
|
||||||
|
try {
|
||||||
|
final Session session = Session.getInstance(obtainProperties(), obtainAuthenticator());
|
||||||
|
|
||||||
|
final MimeMessage mimeMessage = new MimeMessage(session);
|
||||||
|
mimeMessage.setFrom(new InternetAddress(fromEmail, fromName));
|
||||||
|
mimeMessage.setSubject(subject);
|
||||||
|
mimeMessage.setContent(message, "text/html; charset=utf-8");
|
||||||
|
mimeMessage.setSentDate(new Date());
|
||||||
|
|
||||||
|
mimeMessage.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
|
||||||
|
|
||||||
|
this.queue.add(mimeMessage);
|
||||||
|
|
||||||
|
log.info("Mail to " + to + " in queue (size=" + queue.size() + ")");
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Error sending mail", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String prepareSuccessMessage(final CollectionInfo info) {
|
private Properties obtainProperties() {
|
||||||
// TODO Auto-generated method stub
|
final Properties p = new Properties();
|
||||||
return null;
|
p.put("mail.transport.protocol", "smtp");
|
||||||
|
p.put("mail.smtp.host", smtpHost);
|
||||||
|
p.put("mail.smtp.port", smtpPort);
|
||||||
|
p.put("mail.smtp.auth", Boolean.toString(StringUtils.isNotBlank(smtpUser)));
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String prepareFailureMessage(final CollectionInfo info) {
|
private Authenticator obtainAuthenticator() {
|
||||||
// TODO Auto-generated method stub
|
if (StringUtils.isBlank(smtpUser)) { return null; }
|
||||||
return null;
|
|
||||||
|
return new Authenticator() {
|
||||||
|
|
||||||
|
private final PasswordAuthentication authentication = new PasswordAuthentication(smtpUser, smtpPassword);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PasswordAuthentication getPasswordAuthentication() {
|
||||||
|
return authentication;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMail(final String to, final String subject, final String message) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class SimpleUtils {
|
||||||
private static final DateTimeFormatter oaiDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
private static final DateTimeFormatter oaiDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
|
||||||
public static String generateNewJobId() {
|
public static String generateNewJobId() {
|
||||||
return "dump-" + UUID.randomUUID();
|
return "coll-" + UUID.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String oaiFirstUrl(final String baseUrl, final String format, final String setSpec, final LocalDateTime from, final LocalDateTime until) {
|
public static String oaiFirstUrl(final String baseUrl, final String format, final String setSpec, final LocalDateTime from, final LocalDateTime until) {
|
||||||
|
|
|
@ -27,4 +27,10 @@ oai.conf.maxRecords = 1000
|
||||||
|
|
||||||
oai.conf.enable.export.api = true
|
oai.conf.enable.export.api = true
|
||||||
|
|
||||||
|
oai.conf.notification.sender.name = OAI Collector Service
|
||||||
|
oai.conf.notification.sender.email = noreply@openaire.eu
|
||||||
|
oai.conf.notification.smtp.host = localhost
|
||||||
|
oai.conf.notification.smtp.host = 587
|
||||||
|
oai.conf.notification.smtp.user =
|
||||||
|
oai.conf.notification.smtp.password =
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OAI Harvesting Failed</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Hi,<br /><br />
|
||||||
|
your request (<b>ID:</b> <span th:text="${info.oaiBaseUrl}"></span>) to collect metadata from<br />
|
||||||
|
<a th:href="${info.oaiBaseUrl}" th:text="${info.oaiBaseUrl}"></a><br />
|
||||||
|
is failed for the following error:<br />
|
||||||
|
<pre th:text="${info.message}"></pre>
|
||||||
|
<br /><br />
|
||||||
|
<a>Detailed information are available using the following API:</a>
|
||||||
|
<a th:href="${baseUrl} + '/api/history/' + ${info.id}" th:text="${baseUrl} + '/api/history/' + ${info.id}"></a><br />
|
||||||
|
<br /><br />
|
||||||
|
Best Regards.
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
<p>This is an automatically generated message. Please do not reply.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OAI Harvesting Completed</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Hi,<br /><br />
|
||||||
|
your request (<b>ID:</b> <span th:text="${info.id}"></span>) to collect metadata from<br />
|
||||||
|
<a th:href="${info.oaiBaseUrl}" th:text="${info.oaiBaseUrl}"></a><br />
|
||||||
|
has been completed successfully.<br /><br />
|
||||||
|
You can download your file at the address:<br />
|
||||||
|
<a th:href="${info.publicUrl}" th:text="${info.publicUrl}"></a>
|
||||||
|
<br /><br />
|
||||||
|
<a>Detailed information are available using the following API:</a>
|
||||||
|
<a th:href="${baseUrl} + '/api/history/' + ${info.id}" th:text="${baseUrl} + '/api/history/' + ${info.id}"></a><br />
|
||||||
|
<br /><br />
|
||||||
|
Best Regards.
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
<p>This is an automatically generated message. Please do not reply.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue