diff --git a/.gitignore b/.gitignore
index 6dbb6f8..30a8cfc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,6 @@
/sma-server/target/
db/
sma-server.conf
-sma-server.log
+sma-server*.log
.flattened-pom.xml
.idea
diff --git a/sma-client/src/test/java/fr/insalyon/creatis/sma/client/Constants.java b/sma-client/src/test/java/fr/insalyon/creatis/sma/client/Constants.java
index 91eb91d..53a5b01 100644
--- a/sma-client/src/test/java/fr/insalyon/creatis/sma/client/Constants.java
+++ b/sma-client/src/test/java/fr/insalyon/creatis/sma/client/Constants.java
@@ -3,5 +3,5 @@
public final class Constants {
// in millis
- public static int MAX_WAIT_SPAM = 15000;
+ public static final int MAX_WAIT_SPAM_SEC = 15;
}
diff --git a/sma-client/src/test/java/fr/insalyon/creatis/sma/client/SMAClientAndServerTest.java b/sma-client/src/test/java/fr/insalyon/creatis/sma/client/SMAClientAndServerTest.java
index b136f9a..d200bc0 100644
--- a/sma-client/src/test/java/fr/insalyon/creatis/sma/client/SMAClientAndServerTest.java
+++ b/sma-client/src/test/java/fr/insalyon/creatis/sma/client/SMAClientAndServerTest.java
@@ -19,8 +19,8 @@
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetupTest;
-import fr.insalyon.creatis.sma.server.Configuration;
import fr.insalyon.creatis.sma.server.SmaServer;
+import fr.insalyon.creatis.sma.server.utils.Configuration;
import jakarta.mail.internet.MimeMessage;
public class SMAClientAndServerTest {
@@ -42,7 +42,7 @@ private void mockConfig(SmtpServer server) {
when(configuration.getMailProtocol()).thenReturn(server.getProtocol());
when(configuration.getMailHost()).thenReturn(server.getBindTo());
when(configuration.getMailPort()).thenReturn(server.getPort());
- when(configuration.getMailSslTrust()).thenReturn(server.getBindTo());
+ when(configuration.isMailSslTrust()).thenReturn(false);
when(configuration.isMailAuth()).thenReturn(false);
when(configuration.getMailUsername()).thenReturn("");
@@ -50,8 +50,8 @@ private void mockConfig(SmtpServer server) {
when(configuration.getMailFrom()).thenReturn("test@test.com");
when(configuration.getMailFromName()).thenReturn("test");
- when(configuration.getMailMaxRuns()).thenReturn(5);
-
+ when(configuration.getMailMaxRuns()).thenReturn(10);
+ when(configuration.getMailPort()).thenReturn(server.getPort());
Configuration.getInstance().setConfiguration(configuration);
}
@@ -79,10 +79,11 @@ public void spamMailClient() throws Exception {
final String message = "je suis vraiment trop fort";
final String subject = "wow ce titre est incroyable";
final String username = "bliblou";
+ final int nmails = 1000;
String[] randomAddress;
client = new SMAClient(InetAddress.getLocalHost(), configuration.getPort());
- for (int i = 0; i < 1000; i++) {
+ for (int i = 0; i < nmails; i++) {
randomAddress = generateRandomAddress();
client.sendEmail(subject, message, randomAddress, true, username);
System.err.println("Sending mail to : " + randomAddress[0]);
@@ -90,11 +91,11 @@ public void spamMailClient() throws Exception {
before = Instant.now();
System.err.println("Waiting for mails to reach de server !");
- while (mailServer.getReceivedMessages().length != 1000) {
- System.err.println("Waiting !");
+ while (mailServer.getReceivedMessages().length != nmails) {
+ System.err.println("Waiting ! (" + mailServer.getReceivedMessages().length + " mails arrived)");
Thread.sleep(1000);
after = Instant.now();
- assertFalse(Duration.between(before, after).toMillis() > Constants.MAX_WAIT_SPAM);
+ assertFalse(Duration.between(before, after).toSeconds() > Constants.MAX_WAIT_SPAM_SEC);
}
System.err.println("All mails sended !");
diff --git a/sma-common/pom.xml b/sma-common/pom.xml
index 382d8b2..bd17f60 100644
--- a/sma-common/pom.xml
+++ b/sma-common/pom.xml
@@ -12,13 +12,4 @@
sma-common
jar
SMA-Common
-
-
-
- junit
- junit
- 4.10
- test
-
-
diff --git a/sma-server/pom.xml b/sma-server/pom.xml
index 457aaa6..bf250fe 100644
--- a/sma-server/pom.xml
+++ b/sma-server/pom.xml
@@ -66,7 +66,7 @@
com.h2database
h2
- 1.4.177
+ 2.3.232
diff --git a/sma-server/sma-conf.example b/sma-server/sma-conf.example
index c6067b5..170b3a9 100644
--- a/sma-server/sma-conf.example
+++ b/sma-server/sma-conf.example
@@ -5,8 +5,8 @@ mail.transport.protocol = smtps
mail.host = smtp.creatis.insa-lyon.fr
mail.port = 1
-# if an host is trusted, then SSL certificate won't be checked!
-mail.smtp.ssl.trust = localhost
+# if true, then only mail.host will be trusted, SSL certificate won't be checked!
+mail.smtp.ssl.trust = True
mail.auth = True
mail.username = b
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Main.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Main.java
index 9389b38..8a714bc 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Main.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Main.java
@@ -32,10 +32,6 @@
*/
package fr.insalyon.creatis.sma.server;
-/**
- *
- * @author Rafael Ferreira da Silva
- */
public class Main {
public static void main(String[] args) {
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/SmaServer.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/SmaServer.java
index 188bb24..d49d190 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/SmaServer.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/SmaServer.java
@@ -4,51 +4,80 @@
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import fr.insalyon.creatis.sma.common.Communication;
-import fr.insalyon.creatis.sma.server.execution.Executor;
-import fr.insalyon.creatis.sma.server.execution.MessageCleanerPool;
+import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
+import fr.insalyon.creatis.sma.server.dao.MessagePoolDAO;
+import fr.insalyon.creatis.sma.server.dao.h2.MessagePoolData;
+import fr.insalyon.creatis.sma.server.execution.ScheduledTasksCreator;
+import fr.insalyon.creatis.sma.server.execution.executors.CommunicationExecutor;
+import fr.insalyon.creatis.sma.server.utils.Configuration;
+import fr.insalyon.creatis.sma.server.utils.Constants;
-/**
- * SmaServer
- */
public class SmaServer extends Thread {
- private static final Logger logger = Logger.getLogger(Main.class);
+ private static final Logger LOG = Logger.getLogger(Main.class);
+ private final ScheduledExecutorService tasksExecutor;
+ private final ExecutorService socketExecutor;
+ private final ExecutorService sendMessageExecutor;
+ private final Configuration config;
+
+ private final MessagePoolDAO messagePoolDAO;
+ private final MessagePoolBusiness messagePoolBusiness;
private boolean started = false;
+ public SmaServer() {
+ PropertyConfigurator.configure(Main.class.getClassLoader().getResource("smaLog4j.properties"));
+
+ config = Configuration.getInstance();
+ tasksExecutor = Executors.newSingleThreadScheduledExecutor();
+ socketExecutor = Executors.newCachedThreadPool();
+ sendMessageExecutor = Executors.newFixedThreadPool(config.getMailMaxRuns());
+
+ messagePoolDAO = new MessagePoolData();
+ messagePoolBusiness = new MessagePoolBusiness(messagePoolDAO);
+
+ schedule();
+ }
+
public synchronized void waitToBeReady() throws InterruptedException {
while (started == false) {
Thread.sleep(1000);
}
}
+
+ public final void schedule() {
+ ScheduledTasksCreator creator = new ScheduledTasksCreator();
+
+ tasksExecutor.scheduleWithFixedDelay(
+ creator.getPoolCleanerTask(messagePoolDAO), 0, Constants.CLEANER_POOL_SLEEP_HOURS, TimeUnit.HOURS);
+ tasksExecutor.scheduleWithFixedDelay(
+ creator.getMessagePoolTask(sendMessageExecutor, messagePoolDAO, messagePoolBusiness), 0, Constants.MESSAGE_POOL_SLEEP_SECONDS, TimeUnit.SECONDS);
+ }
+
@Override
public void run() {
- PropertyConfigurator.configure(Main.class.getClassLoader().getResource("smaLog4j.properties"));
- Configuration.getInstance();
+ LOG.info("Starting SMA Server on port " + config.getPort());
- logger.info("Starting SMA Server on port " + Configuration.getInstance().getPort());
-
- // Pools
- MessageCleanerPool.getInstance();
-
- // Socket
- try (ServerSocket serverSocket = new ServerSocket(
- Configuration.getInstance().getPort(), 50, InetAddress.getByName("0.0.0.0"))) {
-
+ try (ServerSocket serverSocket = new ServerSocket(config.getPort(), 50, InetAddress.getByName("0.0.0.0"))) {
started = true;
+
while (true) {
Socket socket = serverSocket.accept();
Communication communication = new Communication(socket);
- new Executor(communication).start();
- }
+ socketExecutor.submit(new CommunicationExecutor(communication, messagePoolBusiness));
+ }
} catch (IOException ex) {
- logger.error("Error processing a request ", ex);
+ LOG.error("Error processing a request ", ex);
}
}
-}
\ No newline at end of file
+}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/business/MessagePoolBusiness.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/business/MessagePoolBusiness.java
index 9b13a69..a84b2ce 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/business/MessagePoolBusiness.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/business/MessagePoolBusiness.java
@@ -35,20 +35,9 @@
package fr.insalyon.creatis.sma.server.business;
import fr.insalyon.creatis.sma.common.bean.MessageOperation;
-import fr.insalyon.creatis.sma.server.Configuration;
+import fr.insalyon.creatis.sma.common.bean.OperationStatus;
import fr.insalyon.creatis.sma.server.dao.DAOException;
-import fr.insalyon.creatis.sma.server.dao.DAOFactory;
-import fr.insalyon.creatis.sma.server.execution.MessagePool;
-import java.io.UnsupportedEncodingException;
-import java.util.Date;
-import java.util.Properties;
-import jakarta.mail.Message;
-import jakarta.mail.MessagingException;
-import jakarta.mail.Session;
-import jakarta.mail.Transport;
-import jakarta.mail.internet.InternetAddress;
-import jakarta.mail.internet.MimeMessage;
-import org.apache.log4j.Logger;
+import fr.insalyon.creatis.sma.server.dao.MessagePoolDAO;
/**
*
@@ -56,83 +45,28 @@
*/
public class MessagePoolBusiness {
- private final static Logger logger = Logger.getLogger(MessagePoolBusiness.class);
+ private final MessagePoolDAO messagePoolDAO;
- /**
- *
- * @param operation
- * @throws BusinessException
- */
- public void addOperation(MessageOperation operation) throws BusinessException {
+ public MessagePoolBusiness(MessagePoolDAO messagePoolDAO) {
+ this.messagePoolDAO = messagePoolDAO;
+ }
+ public void addOperation(MessageOperation operation) throws BusinessException {
try {
- DAOFactory.getDAOFactory().getMessagePoolDAO().add(operation);
- MessagePool.getInstance();
+ messagePoolDAO.add(operation);
- } catch (DAOException ex) {
- throw new BusinessException(ex);
+ } catch (DAOException e) {
+ throw new BusinessException(e);
}
}
- public void sendEmail(String ownerEmail, String owner, String subject,
- String content, String[] recipients, boolean direct) throws BusinessException {
- // see https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html
+ public void updateStatus(MessageOperation operation, OperationStatus status) throws BusinessException {
try {
- logger.info("Sending email to: " + String.join(" ", recipients));
- Configuration conf = Configuration.getInstance();
- Properties props = new Properties();
- props.setProperty("mail.transport.protocol", conf.getMailProtocol());
- props.setProperty("mail.smtp.host", conf.getMailHost());
- props.setProperty("mail.smtp.port", String.valueOf(conf.getMailPort()));
- props.setProperty("mail.smtp.auth", String.valueOf(conf.isMailAuth()));
- props.setProperty("mail.smtp.starttls.enable", String.valueOf(conf.isMailAuth()));
- props.setProperty("mail.smtp.ssl.trust", conf.getMailSslTrust());
-
- Session session = Session.getDefaultInstance(props);
- session.setDebug(false);
-
- MimeMessage mimeMessage = new MimeMessage(session);
- mimeMessage.setContent(content, "text/html");
- mimeMessage.addHeader("Content-Type", "text/html");
-
- InternetAddress from = new InternetAddress(ownerEmail, owner);
- mimeMessage.setReplyTo(new InternetAddress[]{from});
- mimeMessage.setFrom(from);
- mimeMessage.setSentDate(new Date());
- mimeMessage.setSubject(subject);
-
- Transport transport = session.getTransport();
-
- if (conf.isMailAuth()) {
- transport.connect(
- conf.getMailHost(), conf.getMailPort(),
- conf.getMailUsername(), conf.getMailPassword());
- } else {
- transport.connect();
- }
-
- InternetAddress[] addressTo = null;
-
- if (recipients != null && recipients.length > 0) {
- addressTo = new InternetAddress[recipients.length];
- for (int i = 0; i < recipients.length; i++) {
- addressTo[i] = new InternetAddress(recipients[i]);
- }
- if (direct) {
- mimeMessage.setRecipients(Message.RecipientType.TO, addressTo);
- } else {
- mimeMessage.setRecipients(Message.RecipientType.BCC, addressTo);
- }
-
- transport.sendMessage(mimeMessage, addressTo);
- transport.close();
+ operation.setStatus(status);
+ messagePoolDAO.update(operation);
- } else {
- logger.warn("There's no recipients to send the email.");
- }
- } catch (UnsupportedEncodingException | MessagingException ex) {
- logger.error(ex);
- throw new BusinessException(ex);
+ } catch (DAOException e){
+ throw new BusinessException(e);
}
}
}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/DAOFactory.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/DAOFactory.java
deleted file mode 100644
index ad3ba54..0000000
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/DAOFactory.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Copyright CNRS-CREATIS
- *
- * Rafael Ferreira da Silva
- * rafael.silva@creatis.insa-lyon.fr
- * http://www.rafaelsilva.com
- *
- * This software is a grid-enabled data-driven workflow manager and editor.
- *
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- */
-package fr.insalyon.creatis.sma.server.dao;
-
-/**
- *
- * @author Rafael Ferreira da Silva
- */
-public abstract class DAOFactory {
-
- private static final int H2 = 1;
- private static int factory = H2;
-
- public static DAOFactory getDAOFactory() {
-
- switch (factory) {
- case H2:
- return H2DAOFactory.getInstance();
- default:
- return null;
- }
- }
-
- protected DAOFactory() {
- connect();
- createTables();
- }
-
- protected abstract void connect();
-
- protected abstract void createTables();
-
- public abstract MessagePoolDAO getMessagePoolDAO();
-}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/H2DAOFactory.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/H2DAOFactory.java
deleted file mode 100644
index 79bf393..0000000
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/H2DAOFactory.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/* Copyright CNRS-CREATIS
- *
- * Rafael Ferreira da Silva
- * rafael.silva@creatis.insa-lyon.fr
- * http://www.rafaelsilva.com
- *
- * This software is a grid-enabled data-driven workflow manager and editor.
- *
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- */
-package fr.insalyon.creatis.sma.server.dao;
-
-import fr.insalyon.creatis.sma.server.dao.h2.MessagePoolData;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.sql.Statement;
-import org.apache.log4j.Logger;
-
-/**
- *
- * @author Rafael Ferreira da Silva
- */
-public class H2DAOFactory extends DAOFactory {
-
- private static final Logger logger = Logger.getLogger(H2DAOFactory.class);
- private static H2DAOFactory instance;
- private final String DRIVER = "org.h2.Driver";
- private final String DBURL = "jdbc:h2:./db/sma.db";
- private Connection connection;
-
- public static H2DAOFactory getInstance() {
- if (instance == null) {
- instance = new H2DAOFactory();
- }
- return instance;
- }
-
- private H2DAOFactory() {
- super();
- }
-
- @Override
- protected void connect() {
- try {
- Class.forName(DRIVER);
- connection = DriverManager.getConnection(DBURL + ";create=true");
- connection.setAutoCommit(true);
-
- } catch (SQLException ex) {
- try {
- connection = DriverManager.getConnection(DBURL);
- connection.setAutoCommit(true);
-
- } catch (SQLException ex1) {
- logException(ex);
- }
- } catch (ClassNotFoundException ex) {
- logException(ex);
- }
- }
-
- @Override
- protected void createTables() {
- try {
- Statement stat = connection.createStatement();
- stat.executeUpdate("CREATE TABLE MessagePool ("
- + "id VARCHAR(100), "
- + "registration TIMESTAMP, "
- + "fromEmail VARCHAR(255), "
- + "fromName VARCHAR(255), "
- + "subject VARCHAR(255), "
- + "contents CLOB, "
- + "recipients CLOB, "
- + "direct BOOLEAN, "
- + "status VARCHAR(50), "
- + "username VARCHAR(255), "
- + "retrycount INT, "
- + "PRIMARY KEY (id)"
- + ")");
- stat.executeUpdate("CREATE INDEX user_idx ON MessagePool(username)");
-
- } catch (SQLException ex) {
- logger.info("Table MessagePool already exists!");
- }
- }
-
- @Override
- public MessagePoolDAO getMessagePoolDAO() {
- return MessagePoolData.getInstance(connection);
- }
-
- private void logException(Exception ex) {
- logger.error(ex);
- if (logger.isDebugEnabled()) {
- for (StackTraceElement stack : ex.getStackTrace()) {
- logger.debug(stack);
- }
- }
- }
-}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/H2Factory.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/H2Factory.java
new file mode 100644
index 0000000..832c1e3
--- /dev/null
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/H2Factory.java
@@ -0,0 +1,102 @@
+/* Copyright CNRS-CREATIS
+ *
+ * Rafael Ferreira da Silva
+ * rafael.silva@creatis.insa-lyon.fr
+ * http://www.rafaelsilva.com
+ *
+ * This software is a grid-enabled data-driven workflow manager and editor.
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+package fr.insalyon.creatis.sma.server.dao.h2;
+
+import fr.insalyon.creatis.sma.server.utils.Constants;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.log4j.Logger;
+import org.h2.jdbcx.JdbcConnectionPool;
+
+/**
+ *
+ * @author Rafael Ferreira da Silva
+ */
+public class H2Factory {
+
+ private static final Logger LOG = Logger.getLogger(H2Factory.class);
+ private static H2Factory instance;
+ private final String DBURL = "jdbc:h2:file:./db/sma.dbl";
+ private JdbcConnectionPool connectionPool;
+
+ public static H2Factory getInstance() {
+ if (instance == null) {
+ instance = new H2Factory();
+ }
+ return instance;
+ }
+
+ private H2Factory() {
+ connectionPool = JdbcConnectionPool.create(DBURL, "sa", "");
+ connectionPool.setMaxConnections(Constants.MAX_DB_CONNECTIONS);
+ connectionPool.setLoginTimeout(Constants.TIMEOUT_POOL_SECONDS);
+
+ createTables();
+ }
+
+ private void createTables() {
+ try (Connection connection = getConnection()) {
+ try (Statement st = connection.createStatement()) {
+ st.executeUpdate("CREATE TABLE MessagePool ("
+ + "id VARCHAR(100), "
+ + "registration TIMESTAMP, "
+ + "fromEmail VARCHAR(255), "
+ + "fromName VARCHAR(255), "
+ + "subject VARCHAR(255), "
+ + "contents CLOB, "
+ + "recipients CLOB, "
+ + "direct BOOLEAN, "
+ + "status VARCHAR(50), "
+ + "username VARCHAR(255), "
+ + "retrycount INT, "
+ + "PRIMARY KEY (id)"
+ + ")");
+ st.executeUpdate("CREATE INDEX user_idx ON MessagePool(username)");
+ }
+ } catch (SQLException ex) {
+ LOG.info("Table MessagePool already exists!");
+ }
+ }
+
+ Connection getConnection() throws SQLException {
+ Connection connection = connectionPool.getConnection();
+
+ connection.setAutoCommit(true);
+ return connection;
+ }
+}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/MessagePoolData.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/MessagePoolData.java
index f2b634e..d5f261c 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/MessagePoolData.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/dao/h2/MessagePoolData.java
@@ -52,29 +52,16 @@
*/
public class MessagePoolData implements MessagePoolDAO {
- private final static Logger logger = Logger.getLogger(MessagePoolData.class);
- private static MessagePoolData instance;
- private Connection connection;
-
- public synchronized static MessagePoolData getInstance(Connection connection) {
- if (instance == null) {
- instance = new MessagePoolData(connection);
- }
- return instance;
- }
-
- private MessagePoolData(Connection connection) {
- this.connection = connection;
- }
+ private final static Logger LOG = Logger.getLogger(MessagePoolData.class);
@Override
public void add(MessageOperation operation) throws DAOException {
+ String query = "INSERT INTO MessagePool(id, registration, fromEmail, fromName, subject, "
+ + "contents, recipients, direct, status, username, retrycount) "
+ + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
- try {
- PreparedStatement ps = connection.prepareStatement("INSERT INTO "
- + "MessagePool(id, registration, fromEmail, fromName, subject, "
- + "contents, recipients, direct, status, username, retrycount) "
- + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ try (Connection connection = H2Factory.getInstance().getConnection();
+ PreparedStatement ps = connection.prepareStatement(query)) {
ps.setString(1, operation.getId());
ps.setTimestamp(2, new Timestamp(operation.getRegistration().getTime()));
@@ -87,24 +74,23 @@ public void add(MessageOperation operation) throws DAOException {
ps.setString(9, operation.getStatus().name());
ps.setString(10, operation.getUsername());
ps.setInt(11, operation.getRetryCount());
- ps.execute();
- ps.close();
+ ps.executeUpdate();
} catch (SQLException ex) {
- logger.error(ex);
+ LOG.error(ex);
throw new DAOException(ex);
}
}
@Override
public void update(MessageOperation operation) throws DAOException {
+ String query = "UPDATE MessagePool SET registration = ?, fromEmail = ?, fromName = ?, "
+ + "subject = ?, contents = ?, recipients = ?, direct = ?, "
+ + "status = ?, username = ?, retrycount = ? WHERE id = ?";
+
+ try (Connection connection = H2Factory.getInstance().getConnection();
+ PreparedStatement ps = connection.prepareStatement(query)) {
- try {
- PreparedStatement ps = connection.prepareStatement("UPDATE MessagePool "
- + "SET registration = ?, fromEmail = ?, fromName = ?, "
- + "subject = ?, contents = ?, recipients = ?, direct = ?, "
- + "status = ?, username = ?, retrycount = ? "
- + "WHERE id = ?");
ps.setTimestamp(1, new Timestamp(operation.getRegistration().getTime()));
ps.setString(2, operation.getFromEmail());
ps.setString(3, operation.getFromName());
@@ -117,38 +103,36 @@ public void update(MessageOperation operation) throws DAOException {
ps.setInt(10, operation.getRetryCount());
ps.setString(11, operation.getId());
ps.executeUpdate();
- ps.close();
} catch (SQLException ex) {
- logger.error(ex);
+ LOG.error(ex);
throw new DAOException(ex);
}
}
@Override
public void remove(MessageOperation operation) throws DAOException {
- try {
- PreparedStatement ps = connection.prepareStatement("DELETE "
- + "FROM MessagePool WHERE id=?");
+ String query = "DELETE FROM MessagePool WHERE id=?";
+
+ try (Connection connection = H2Factory.getInstance().getConnection();
+ PreparedStatement ps = connection.prepareStatement(query)) {
ps.setString(1, operation.getId());
ps.execute();
- ps.close();
} catch (SQLException ex) {
- logger.error(ex);
+ LOG.error(ex);
throw new DAOException(ex);
}
}
@Override
public List getPendingOperations() throws DAOException {
+ String query = getSelect() + "WHERE status = ? OR STATUS = ? ORDER BY registration";
- try {
+ try (Connection connection = H2Factory.getInstance().getConnection();
+ PreparedStatement ps = connection.prepareStatement(query)) {
- PreparedStatement ps = connection.prepareStatement(getSelect()
- + "WHERE status = ? OR status = ? "
- + "ORDER BY registration");
ps.setString(1, OperationStatus.Queued.name());
ps.setString(2, OperationStatus.Rescheduled.name());
@@ -157,38 +141,35 @@ public List getPendingOperations() throws DAOException {
while (rs.next()) {
operations.add(getMessageOperation(rs));
}
- ps.close();
return operations;
} catch (SQLException ex) {
- logger.error(ex);
+ LOG.error(ex);
throw new DAOException(ex);
}
}
@Override
public List getOldOperations(Date date) throws DAOException {
+ List operations = new ArrayList();
+ String query = getSelect() + "WHERE registration < ? AND (status = ? OR status = ?)"
+ + "ORDER BY registration";
- try {
- List operations = new ArrayList();
- PreparedStatement ps = connection.prepareStatement(
- getSelect()
- + "WHERE registration < ? "
- + "AND (status = ? OR status = ?)"
- + "ORDER BY registration");
+ try (Connection connection = H2Factory.getInstance().getConnection();
+ PreparedStatement ps = connection.prepareStatement(query)) {
ps.setTimestamp(1, new Timestamp(date.getTime()));
ps.setString(2, OperationStatus.Done.name());
ps.setString(3, OperationStatus.Failed.name());
+
ResultSet rs = ps.executeQuery();
while (rs.next()) {
operations.add(getMessageOperation(rs));
}
- ps.close();
return operations;
} catch (SQLException ex) {
- logger.error(ex);
+ LOG.error(ex);
throw new DAOException(ex);
}
}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Command.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Command.java
index e0aea6d..e84ee3a 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Command.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Command.java
@@ -45,7 +45,6 @@ public abstract class Command {
protected Communication communication;
protected Command(Communication communication) {
-
this.communication = communication;
}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessageCleanerPool.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessageCleanerPool.java
deleted file mode 100644
index d50d22a..0000000
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessageCleanerPool.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright CNRS-CREATIS
- *
- * Rafael Ferreira da Silva
- * rafael.silva@creatis.insa-lyon.fr
- * http://www.rafaelsilva.com
- *
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- */
-package fr.insalyon.creatis.sma.server.execution;
-
-import fr.insalyon.creatis.sma.common.bean.MessageOperation;
-import fr.insalyon.creatis.sma.server.Configuration;
-import fr.insalyon.creatis.sma.server.dao.DAOException;
-import fr.insalyon.creatis.sma.server.dao.DAOFactory;
-import fr.insalyon.creatis.sma.server.dao.MessagePoolDAO;
-import java.util.Calendar;
-import org.apache.log4j.Logger;
-
-/**
- *
- * @author Rafael Ferreira da Silva
- */
-public class MessageCleanerPool extends Thread {
-
- private static final Logger logger = Logger.getLogger(MessagePool.class);
- private static MessageCleanerPool instance;
- private volatile boolean stop;
- private MessagePoolDAO messagePoolDAO;
-
- public static MessageCleanerPool getInstance() {
-
- if (instance == null) {
- instance = new MessageCleanerPool();
- instance.start();
- }
- return instance;
- }
-
- private MessageCleanerPool() {
-
- this.stop = false;
- }
-
- @Override
- public void run() {
-
- while (!stop) {
- try {
- Calendar cal = Calendar.getInstance();
- cal.add(Calendar.DATE, -(Configuration.getInstance().getMaxHistory()));
-
- messagePoolDAO = DAOFactory.getDAOFactory().getMessagePoolDAO();
-
- for (MessageOperation operation : messagePoolDAO.getOldOperations(cal.getTime())) {
- messagePoolDAO.remove(operation);
- logger.info("Removed: " + operation.getRegistration()
- + ", FROM: " + operation.getFromName()
- + ", TO: " + operation.getRecipientsAsString());
- }
-
- } catch (DAOException ex) {
- // do nothing
- }
-
- try {
- sleep(86400000);
- } catch (InterruptedException ex) {
- logger.error(ex);
- }
- }
- instance = null;
- }
-}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessagePool.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessagePool.java
deleted file mode 100644
index 036f080..0000000
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/MessagePool.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Copyright CNRS-CREATIS
- *
- * Rafael Ferreira da Silva
- * rafael.silva@creatis.insa-lyon.fr
- * http://www.rafaelsilva.com
- *
- * This software is governed by the CeCILL license under French law and
- * abiding by the rules of distribution of free software. You can use,
- * modify and/ or redistribute the software under the terms of the CeCILL
- * license as circulated by CEA, CNRS and INRIA at the following URL
- * "http://www.cecill.info".
- *
- * As a counterpart to the access to the source code and rights to copy,
- * modify and redistribute granted by the license, users are provided only
- * with a limited warranty and the software's author, the holder of the
- * economic rights, and the successive licensors have only limited
- * liability.
- *
- * In this respect, the user's attention is drawn to the risks associated
- * with loading, using, modifying and/or developing or reproducing the
- * software by the user in light of its specific status of free software,
- * that may mean that it is complicated to manipulate, and that also
- * therefore means that it is reserved for developers and experienced
- * professionals having in-depth computer knowledge. Users are therefore
- * encouraged to load and test the software's suitability as regards their
- * requirements in conditions enabling the security of their systems and/or
- * data to be ensured and, more generally, to use and operate it in the
- * same conditions as regards security.
- *
- * The fact that you are presently reading this means that you have had
- * knowledge of the CeCILL license and that you accept its terms.
- */
-package fr.insalyon.creatis.sma.server.execution;
-
-import fr.insalyon.creatis.sma.common.bean.MessageOperation;
-import fr.insalyon.creatis.sma.common.bean.OperationStatus;
-import fr.insalyon.creatis.sma.server.Configuration;
-import fr.insalyon.creatis.sma.server.business.BusinessException;
-import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
-import fr.insalyon.creatis.sma.server.dao.DAOException;
-import fr.insalyon.creatis.sma.server.dao.DAOFactory;
-import fr.insalyon.creatis.sma.server.dao.MessagePoolDAO;
-import java.util.List;
-import org.apache.log4j.Logger;
-
-/**
- *
- * @author Rafael Ferreira da Silva
- */
-public class MessagePool extends Thread {
-
- private static final Logger logger = Logger.getLogger(MessagePool.class);
- private static MessagePool instance;
- private MessagePoolDAO messagePoolDAO;
- private static volatile int running = 0;
-
- public static MessagePool getInstance() {
-
- if (instance == null) {
- instance = new MessagePool();
- instance.start();
- }
- return instance;
- }
-
- private MessagePool() {
- }
-
- @Override
- public void run() {
-
- try {
- messagePoolDAO = DAOFactory.getDAOFactory().getMessagePoolDAO();
- List pendingOperations = messagePoolDAO.getPendingOperations();
-
- while (!pendingOperations.isEmpty()) {
-
- for (MessageOperation mo : pendingOperations) {
- if (running < Configuration.getInstance().getMailMaxRuns()) {
- running++;
- logger.info("[MessagePool] Processing operation '" + mo.getId() + "'.");
- updateStatus(mo, OperationStatus.Running);
- new Execute(mo).start();
- } else {
- break;
- }
- }
- pendingOperations = messagePoolDAO.getPendingOperations();
- }
- } catch (DAOException ex) {
- // do nothing
- }
- instance = null;
- }
-
- private void updateStatus(MessageOperation operation, OperationStatus status) throws DAOException {
-
- operation.setStatus(status);
- messagePoolDAO.update(operation);
- }
-
- class Execute extends Thread {
-
- private MessageOperation operation;
-
- public Execute(MessageOperation operation) {
- this.operation = operation;
- }
-
- @Override
- public void run() {
-
- try {
- new MessagePoolBusiness().sendEmail(
- operation.getFromEmail(),
- operation.getFromName(),
- operation.getSubject(),
- operation.getContents(),
- operation.getRecipients(),
- operation.isDirect());
- updateStatus(operation, OperationStatus.Done);
-
- } catch (DAOException | BusinessException ex) {
- logger.error(ex);
- retry();
- } finally {
- running--;
- MessagePool.getInstance();
- }
- }
-
- private void retry() {
-
- try {
- if (operation.getRetryCount() == Configuration.getInstance().getMaxRetryCount()) {
- updateStatus(operation, OperationStatus.Failed);
- } else {
- operation.incrementRetryCount();
- updateStatus(operation, OperationStatus.Rescheduled);
- }
- } catch (DAOException ex) {
- // do nothing
- }
- }
- }
-}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/ScheduledTasksCreator.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/ScheduledTasksCreator.java
new file mode 100644
index 0000000..ab694dc
--- /dev/null
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/ScheduledTasksCreator.java
@@ -0,0 +1,116 @@
+/* Copyright CNRS-CREATIS
+ *
+ * Rafael Ferreira da Silva
+ * rafael.silva@creatis.insa-lyon.fr
+ * http://www.rafaelsilva.com
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+package fr.insalyon.creatis.sma.server.execution;
+
+import fr.insalyon.creatis.sma.common.bean.MessageOperation;
+import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
+import fr.insalyon.creatis.sma.server.dao.DAOException;
+import fr.insalyon.creatis.sma.server.dao.MessagePoolDAO;
+import fr.insalyon.creatis.sma.server.execution.executors.MessageExecutor;
+import fr.insalyon.creatis.sma.server.utils.Configuration;
+import fr.insalyon.creatis.sma.server.utils.Constants;
+
+import java.util.Calendar;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.log4j.Logger;
+
+public class ScheduledTasksCreator {
+
+ private static final Logger LOG = Logger.getLogger(ScheduledTasksCreator.class);
+
+ public PoolCleaner getPoolCleanerTask(MessagePoolDAO messagePoolDAO) {
+ return new PoolCleaner(messagePoolDAO);
+ }
+
+ public MessagePool getMessagePoolTask(ExecutorService executorService, MessagePoolDAO messagePoolDAO, MessagePoolBusiness messagePoolBusiness) {
+ return new MessagePool(executorService, messagePoolDAO, messagePoolBusiness);
+ }
+
+ public static class PoolCleaner implements Runnable {
+ private final MessagePoolDAO messagePoolDAO;
+
+ public PoolCleaner(MessagePoolDAO messagePoolDAO) {
+ this.messagePoolDAO = messagePoolDAO;
+ }
+
+ @Override
+ public void run() {
+ LOG.info("Running Message Cleaner Pool");
+
+ try {
+ Calendar cal = Calendar.getInstance();
+ cal.add(Calendar.DATE, - (Configuration.getInstance().getMaxHistory()));
+
+ for (MessageOperation operation : messagePoolDAO.getOldOperations(cal.getTime())) {
+ messagePoolDAO.remove(operation);
+ LOG.info("Removed: " + operation.getRegistration()
+ + ", FROM: " + operation.getFromName()
+ + ", TO: " + operation.getRecipientsAsString());
+ }
+
+ } catch (DAOException e) {
+ LOG.warn("Failed to run Message Cleaner Pool properly!", e);
+ } finally {
+ LOG.info("Finishing Message Cleaner Pool");
+ }
+ }
+ }
+
+ public static class MessagePool implements Runnable {
+ private final ExecutorService executor;
+ private final MessagePoolDAO messagePoolDAO;
+ private final MessagePoolBusiness messagePoolBusiness;
+
+ public MessagePool(ExecutorService executorService, MessagePoolDAO messagePoolDAO, MessagePoolBusiness messagePoolBusiness) {
+ this.executor = executorService;
+ this.messagePoolDAO = messagePoolDAO;
+ this.messagePoolBusiness = messagePoolBusiness;
+ }
+
+ @Override
+ public void run() {
+ try {
+ List callablesOperations = messagePoolDAO.getPendingOperations().stream()
+ .map(op -> new MessageExecutor(op, messagePoolBusiness)).toList();
+
+ executor.invokeAll(callablesOperations, Constants.MESSAGE_POOL_MAX_WAIT_SECONDS, TimeUnit.SECONDS);
+
+ } catch (DAOException | InterruptedException e) {
+ LOG.warn("Failed to run Message Pool properly!", e);
+ }
+ }
+ }
+}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/command/SendEmailCommand.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/command/SendEmailCommand.java
index 37a1c1e..f8e2b69 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/command/SendEmailCommand.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/command/SendEmailCommand.java
@@ -36,10 +36,10 @@
import fr.insalyon.creatis.sma.common.Communication;
import fr.insalyon.creatis.sma.common.bean.MessageOperation;
-import fr.insalyon.creatis.sma.server.Configuration;
import fr.insalyon.creatis.sma.server.business.BusinessException;
import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
import fr.insalyon.creatis.sma.server.execution.Command;
+import fr.insalyon.creatis.sma.server.utils.Configuration;
/**
*
@@ -47,14 +47,15 @@
*/
public class SendEmailCommand extends Command {
- private String subject;
- private String contents;
- private String recipients;
- private boolean direct;
- private String username;
+ private final String subject;
+ private final String contents;
+ private final String recipients;
+ private final boolean direct;
+ private final String username;
+ private final MessagePoolBusiness poolBusiness;
- public SendEmailCommand(Communication communication, String subject,
- String contents, String recipients, String direct, String username) {
+ public SendEmailCommand(Communication communication, MessagePoolBusiness poolBusiness,
+ String subject, String contents, String recipients, String direct, String username) {
super(communication);
this.subject = subject;
@@ -62,6 +63,7 @@ public SendEmailCommand(Communication communication, String subject,
this.recipients = recipients;
this.direct = Boolean.valueOf(direct);
this.username = username;
+ this.poolBusiness = poolBusiness;
}
@Override
@@ -71,7 +73,7 @@ public void execute() {
Configuration.getInstance().getMailFrom(),
Configuration.getInstance().getMailFromName(),
subject, contents, recipients, direct, username);
- new MessagePoolBusiness().addOperation(operation);
+ poolBusiness.addOperation(operation);
communication.sendMessage(operation.getId());
communication.sendSucessMessage();
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Executor.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/CommunicationExecutor.java
similarity index 81%
rename from sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Executor.java
rename to sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/CommunicationExecutor.java
index 267db88..5fa3da2 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/Executor.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/CommunicationExecutor.java
@@ -32,11 +32,13 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
-package fr.insalyon.creatis.sma.server.execution;
+package fr.insalyon.creatis.sma.server.execution.executors;
import fr.insalyon.creatis.sma.common.Communication;
import fr.insalyon.creatis.sma.common.Constants;
import fr.insalyon.creatis.sma.common.ExecutorConstants;
+import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
+import fr.insalyon.creatis.sma.server.execution.Command;
import fr.insalyon.creatis.sma.server.execution.command.SendEmailCommand;
import java.io.IOException;
import org.apache.log4j.Logger;
@@ -45,13 +47,15 @@
*
* @author Rafael Ferreira da Silva
*/
-public class Executor extends Thread {
+public class CommunicationExecutor extends Thread {
- private static final Logger logger = Logger.getLogger(Executor.class);
- private Communication communication;
+ private static final Logger LOG = Logger.getLogger(CommunicationExecutor.class);
+ private final Communication communication;
+ private final MessagePoolBusiness poolBusiness;
- public Executor(Communication communication) {
+ public CommunicationExecutor(Communication communication, MessagePoolBusiness poolBusiness) {
this.communication = communication;
+ this.poolBusiness = poolBusiness;
}
@Override
@@ -68,23 +72,17 @@ public void run() {
logException(new Exception("Error during message receive: " + message));
}
} catch (IOException ex) {
- logger.error(ex);
+ LOG.error(ex);
} finally {
try {
communication.close();
} catch (IOException ex) {
- logger.error(ex);
+ LOG.error(ex);
}
}
}
- /**
- *
- * @param message
- * @return
- */
private Command parseCommand(String message) {
-
try {
String[] tk = message.split(Constants.MSG_SEP_1);
int command = Integer.parseInt(tk[0]);
@@ -92,7 +90,7 @@ private Command parseCommand(String message) {
switch (command) {
case ExecutorConstants.MESSAGEPOOL_ADD_OPERATION:
- return new SendEmailCommand(communication, tk[1], tk[2], tk[3], tk[4], tk[5]);
+ return new SendEmailCommand(communication, poolBusiness, tk[1], tk[2], tk[3], tk[4], tk[5]);
default:
logException(new Exception("Command not recognized: " + message));
@@ -106,20 +104,10 @@ private Command parseCommand(String message) {
return null;
}
- /**
- *
- * @param ex
- */
private void logException(Exception ex) {
-
communication.sendErrorMessage(ex.getMessage());
communication.sendEndOfMessage();
- logger.error(ex.getMessage());
- if (logger.isDebugEnabled()) {
- for (StackTraceElement stack : ex.getStackTrace()) {
- logger.debug(stack);
- }
- }
+ LOG.error("Exception occured", ex);
}
}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/MessageExecutor.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/MessageExecutor.java
new file mode 100644
index 0000000..e0aad52
--- /dev/null
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/execution/executors/MessageExecutor.java
@@ -0,0 +1,160 @@
+/* Copyright CNRS-CREATIS
+ *
+ * Rafael Ferreira da Silva
+ * rafael.silva@creatis.insa-lyon.fr
+ * http://www.rafaelsilva.com
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ */
+package fr.insalyon.creatis.sma.server.execution.executors;
+
+import fr.insalyon.creatis.sma.common.bean.MessageOperation;
+import fr.insalyon.creatis.sma.common.bean.OperationStatus;
+import fr.insalyon.creatis.sma.server.business.BusinessException;
+import fr.insalyon.creatis.sma.server.business.MessagePoolBusiness;
+import fr.insalyon.creatis.sma.server.utils.Configuration;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Properties;
+import java.util.concurrent.Callable;
+
+import org.apache.log4j.Logger;
+
+public class MessageExecutor implements Callable {
+
+ private static final Logger LOG = Logger.getLogger(MessageExecutor.class);
+ private final MessageOperation operation;
+ private final MessagePoolBusiness poolBusiness;
+
+ public MessageExecutor(MessageOperation operation, MessagePoolBusiness messagePoolBusiness) {
+ this.operation = operation;
+ this.poolBusiness = messagePoolBusiness;
+ }
+
+ @Override
+ public Void call() throws Exception {
+ LOG.info("[MessagePool] Processing operation '" + operation.getId() + "'.");
+
+ try {
+ poolBusiness.updateStatus(operation, OperationStatus.Running);
+ sendEmail(
+ operation.getFromEmail(),
+ operation.getFromName(),
+ operation.getSubject(),
+ operation.getContents(),
+ operation.getRecipients(),
+ operation.isDirect());
+ poolBusiness.updateStatus(operation, OperationStatus.Done);
+
+ } catch (BusinessException ex) {
+ LOG.error(ex);
+ retry();
+ }
+ return null;
+ }
+
+ public void sendEmail(String ownerEmail, String owner, String subject,
+ String content, String[] recipients, boolean direct) throws BusinessException {
+ // see https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html
+ try {
+ LOG.info("Sending email to: " + String.join(" ", recipients));
+ Configuration conf = Configuration.getInstance();
+ Properties props = new Properties();
+ props.setProperty("mail.transport.protocol", conf.getMailProtocol());
+ props.setProperty("mail.smtp.host", conf.getMailHost());
+ props.setProperty("mail.smtp.port", String.valueOf(conf.getMailPort()));
+ props.setProperty("mail.smtp.auth", String.valueOf(conf.isMailAuth()));
+ props.setProperty("mail.smtp.starttls.enable", String.valueOf(conf.isMailAuth()));
+
+ if (conf.isMailSslTrust()) {
+ props.setProperty("mail.smtp.ssl.trust", conf.getMailHost());
+ }
+
+ Session session = Session.getDefaultInstance(props);
+ session.setDebug(false);
+
+ MimeMessage mimeMessage = new MimeMessage(session);
+ mimeMessage.setContent(content, "text/html");
+ mimeMessage.addHeader("Content-Type", "text/html");
+
+ InternetAddress from = new InternetAddress(ownerEmail, owner);
+ mimeMessage.setReplyTo(new InternetAddress[]{from});
+ mimeMessage.setFrom(from);
+ mimeMessage.setSentDate(new Date());
+ mimeMessage.setSubject(subject);
+
+ Transport transport = session.getTransport();
+
+ if (conf.isMailAuth()) {
+ transport.connect(
+ conf.getMailHost(), conf.getMailPort(),
+ conf.getMailUsername(), conf.getMailPassword());
+ } else {
+ transport.connect();
+ }
+
+ InternetAddress[] addressTo = null;
+
+ if (recipients != null && recipients.length > 0) {
+ addressTo = new InternetAddress[recipients.length];
+ for (int i = 0; i < recipients.length; i++) {
+ addressTo[i] = new InternetAddress(recipients[i]);
+ }
+ if (direct) {
+ mimeMessage.setRecipients(Message.RecipientType.TO, addressTo);
+ } else {
+ mimeMessage.setRecipients(Message.RecipientType.BCC, addressTo);
+ }
+
+ transport.sendMessage(mimeMessage, addressTo);
+ transport.close();
+
+ } else {
+ LOG.warn("There's no recipients to send the email.");
+ }
+ } catch (UnsupportedEncodingException | MessagingException ex) {
+ LOG.error(ex);
+ throw new BusinessException(ex);
+ }
+ }
+
+ public void retry() throws BusinessException {
+ if (operation.getRetryCount() == Configuration.getInstance().getMaxRetryCount()) {
+ poolBusiness.updateStatus(operation, OperationStatus.Failed);
+ } else {
+ operation.incrementRetryCount();
+ poolBusiness.updateStatus(operation, OperationStatus.Rescheduled);
+ }
+ }
+}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Configuration.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Configuration.java
similarity index 93%
rename from sma-server/src/main/java/fr/insalyon/creatis/sma/server/Configuration.java
rename to sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Configuration.java
index 296e610..9470f76 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Configuration.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Configuration.java
@@ -30,7 +30,7 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
-package fr.insalyon.creatis.sma.server;
+package fr.insalyon.creatis.sma.server.utils;
import java.io.File;
import org.apache.commons.configuration.ConfigurationException;
@@ -43,7 +43,7 @@
*/
public class Configuration {
- private static final Logger logger = Logger.getLogger(Configuration.class);
+ private static final Logger LOG = Logger.getLogger(Configuration.class);
private static Configuration instance;
private static final String confFile = "sma-server.conf";
// General
@@ -52,8 +52,8 @@ public class Configuration {
private int maxRetryCount;
private int mailPort;
private boolean mailAuth;
+ private boolean mailSslTrust;
private String mailHost;
- private String mailSslTrust;
private String mailUsername;
private String mailPassword;
private String mailProtocol;
@@ -62,7 +62,6 @@ public class Configuration {
private int mailMaxRuns;
public static Configuration getInstance() {
-
if (instance == null) {
instance = new Configuration();
}
@@ -75,7 +74,7 @@ public void setConfiguration(Configuration config) {
private Configuration() {
try {
- logger.info("Loading configuration file.");
+ LOG.info("Loading configuration file.");
PropertiesConfiguration config = new PropertiesConfiguration(new File(confFile));
port = config.getInt(Constants.LAB_AGENT_PORT, 8082);
@@ -85,12 +84,12 @@ private Configuration() {
maxHistory = config.getInt(Constants.LAB_AGENT_MAX_HISTORY, 90);
maxRetryCount = config.getInt(Constants.LAB_AGENT_RETRYCOUNT, 5);
mailHost = config.getString(Constants.LAB_MAIL_HOST, "smtp.localhost");
- mailSslTrust = config.getString(Constants.LAB_MAIL_SSL_TRUST, "");
+ mailSslTrust = config.getBoolean(Constants.LAB_MAIL_SSL_TRUST, false);
mailPort = config.getInt(Constants.LAB_MAIL_PORT, 25);
mailProtocol = config.getString(Constants.LAB_MAIL_PROTOCOL, "smtp");
mailFrom = config.getString(Constants.LAB_MAIL_FROM, "example@example.com");
mailFromName = config.getString(Constants.LAB_MAIL_FROM_NAME, "Example");
- mailMaxRuns = config.getInt(Constants.LAB_MAIL_MAX_RUNS, 5);
+ mailMaxRuns = config.getInt(Constants.LAB_MAIL_MAX_RUNS, 50);
config.setProperty(Constants.LAB_AGENT_PORT, port);
config.setProperty(Constants.LAB_AGENT_RETRYCOUNT, maxRetryCount);
@@ -112,7 +111,7 @@ private Configuration() {
config.save();
} catch (ConfigurationException ex) {
- logger.error(ex);
+ LOG.error(ex);
}
}
@@ -136,7 +135,7 @@ public String getMailHost() {
return mailHost;
}
- public String getMailSslTrust() {
+ public boolean isMailSslTrust() {
return mailSslTrust;
}
diff --git a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Constants.java b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Constants.java
similarity index 88%
rename from sma-server/src/main/java/fr/insalyon/creatis/sma/server/Constants.java
rename to sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Constants.java
index fc5dba0..69923c6 100644
--- a/sma-server/src/main/java/fr/insalyon/creatis/sma/server/Constants.java
+++ b/sma-server/src/main/java/fr/insalyon/creatis/sma/server/utils/Constants.java
@@ -30,7 +30,7 @@
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*/
-package fr.insalyon.creatis.sma.server;
+package fr.insalyon.creatis.sma.server.utils;
/**
*
@@ -49,6 +49,12 @@ public class Constants {
public static final String LAB_MAIL_FROM = "mail.from";
public static final String LAB_MAIL_FROM_NAME = "mail.from.name";
public static final String LAB_MAIL_MAX_RUNS = "mail.max.simultaneous.runs";
+
+ public static final int CLEANER_POOL_SLEEP_HOURS = 24;
+ public static final int MESSAGE_POOL_SLEEP_SECONDS = 2;
+ public static final int MESSAGE_POOL_MAX_WAIT_SECONDS = 60;
+ public static final int TIMEOUT_POOL_SECONDS = 30;
+ public static final int MAX_DB_CONNECTIONS = 25;
public static final String LAB_MAIL_AUTH = "mail.auth";
public static final String LAB_MAIL_SSL_TRUST = "mail.smtp.ssl.trust";
}