diff --git a/pom.xml b/pom.xml
index 619a2028..92cc8305 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,8 @@
UTF-8
21
21
+
+ 6.2.10
@@ -50,6 +52,19 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.13.0
+
+
+ -parameters
+ -Xlint:deprecation
+ -Werror
+
+
+
+
org.apache.maven.plugins
maven-dependency-plugin
@@ -102,66 +117,67 @@
- commons-configuration
- commons-configuration
- 1.9
-
-
- commons-logging
- commons-logging
-
-
+ org.hibernate.orm
+ hibernate-core
+ 6.6.0.Final
- org.slf4j
- jcl-over-slf4j
- 2.0.17
+ org.mockito
+ mockito-junit-jupiter
+ 5.13.0
+ test
- commons-io
- commons-io
- 2.17.0
+ org.junit.jupiter
+ junit-jupiter
+ 5.11.0
+ test
- code.google.com
- jspf.core
- 1.0.2
+ com.h2database
+ h2
+ 2.3.232
+ test
- org.hibernate
- hibernate-core
- 6.6.0.Final
+ org.springframework
+ spring-test
+ ${spring-framework.version}
+ test
- org.apache.velocity
- velocity
- 1.7
+ org.springframework
+ spring-context
+ ${spring-framework.version}
- org.junit.jupiter
- junit-jupiter-api
- 5.11.3
- test
+ org.springframework
+ spring-jdbc
+ ${spring-framework.version}
- org.mockito
- mockito-junit-jupiter
- 5.13.0
- test
+ org.springframework
+ spring-orm
+ ${spring-framework.version}
- com.h2database
- h2
- 2.3.232
- test
+ jakarta.annotation
+ jakarta.annotation-api
+ 3.0.0
+
+
+
+ com.zaxxer
+ HikariCP
+ 7.0.2
diff --git a/src/main/java/fr/insalyon/creatis/gasw/DatabaseConfiguration.java b/src/main/java/fr/insalyon/creatis/gasw/DatabaseConfiguration.java
new file mode 100644
index 00000000..5d65a12f
--- /dev/null
+++ b/src/main/java/fr/insalyon/creatis/gasw/DatabaseConfiguration.java
@@ -0,0 +1,69 @@
+package fr.insalyon.creatis.gasw;
+
+import com.zaxxer.hikari.HikariDataSource;
+import fr.insalyon.creatis.gasw.plugin.DatabasePlugin;
+import jakarta.persistence.EntityManagerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+import java.util.Properties;
+
+@Configuration
+public class DatabaseConfiguration {
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final DatabasePlugin dbPlugin;
+
+ public DatabaseConfiguration(DatabasePlugin dbPlugin) {
+ this.dbPlugin = dbPlugin;
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ logger.info("Loading database plugin '{}' version '{}'",
+ dbPlugin.getName(), dbPlugin.getClass().getPackage().getImplementationVersion());
+
+ HikariDataSource dataSource = new HikariDataSource();
+ dataSource.setDriverClassName(dbPlugin.getDriverClass());
+ dataSource.setUsername(dbPlugin.getUserName());
+ dataSource.setPassword(dbPlugin.getPassword());
+ dataSource.setJdbcUrl(dbPlugin.getConnectionUrl());
+ return dataSource;
+ }
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
+ LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
+ emf.setDataSource(dataSource);
+ emf.setPackagesToScan(
+ "fr.insalyon.creatis.gasw.bean",
+ "fr.insalyon.creatis.gasw.plugin"
+ );
+
+ emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
+ emf.setJpaProperties(hibernateProperties());
+ return emf;
+ }
+
+ private Properties hibernateProperties() {
+ Properties properties = new Properties();
+ properties.setProperty("hibernate.default_schema", dbPlugin.getSchema());
+ properties.setProperty("hibernate.hbm2ddl.auto", "update");
+ properties.setProperty("hibernate.show_sql", "false");
+ properties.setProperty("hibernate.format_sql", "false");
+ return properties;
+ }
+
+ @Bean
+ public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
+ return new JpaTransactionManager(emf);
+ }
+}
diff --git a/src/main/java/fr/insalyon/creatis/gasw/Gasw.java b/src/main/java/fr/insalyon/creatis/gasw/Gasw.java
index cf0fa7c8..b8c69fb2 100644
--- a/src/main/java/fr/insalyon/creatis/gasw/Gasw.java
+++ b/src/main/java/fr/insalyon/creatis/gasw/Gasw.java
@@ -32,70 +32,143 @@
*/
package fr.insalyon.creatis.gasw;
+import fr.insalyon.creatis.gasw.bean.SEEntryPoint;
+import fr.insalyon.creatis.gasw.bean.SEEntryPointID;
+import fr.insalyon.creatis.gasw.dao.DAOException;
+import fr.insalyon.creatis.gasw.dao.SEEntryPointsDAO;
import fr.insalyon.creatis.gasw.execution.ExecutorFactory;
-import fr.insalyon.creatis.gasw.execution.FailOver;
import fr.insalyon.creatis.gasw.plugin.ExecutorPlugin;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.List;
+
+import fr.insalyon.creatis.gasw.plugin.ListenerPlugin;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+@Service
public class Gasw {
- private static final Logger logger = LoggerFactory.getLogger(Gasw.class);
- private static Gasw instance;
- private GaswNotification notification;
-
- /**
- * Gets a default instance of GASW.
- *
- * @return Instance of GASW
- */
- public synchronized static Gasw getInstance() throws GaswException {
-
- if (instance == null) {
- instance = new Gasw();
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ private final GaswConfiguration config;
+ private final GaswNotification gaswNotification;
+ private final ExecutorFactory executorFactory;
+ private final SEEntryPointsDAO seEntryPointsDAO;
+ private final List executorPlugins;
+ private final List listenerPlugins;
+
+ public Gasw(GaswConfiguration config, GaswNotification gaswNotification, ExecutorFactory executorFactory,
+ SEEntryPointsDAO seEntryPointsDAO, List executorPlugins, List listenerPlugins) {
+ this.config = config;
+ this.gaswNotification = gaswNotification;
+ this.executorFactory = executorFactory;
+ this.seEntryPointsDAO = seEntryPointsDAO;
+ this.executorPlugins = executorPlugins;
+ this.listenerPlugins = listenerPlugins;
+ }
+
+ @PostConstruct
+ public void init() throws GaswException {
+ if (config.isFailOverEnabled()) {
+ loadSEEntryPoints();
}
- return instance;
}
- private Gasw() throws GaswException {
- try {
- logger.info("Initializing GASW.");
- GaswConfiguration.getInstance().loadHibernate();
+ // Log loaded plugins after all beans creation
+ @EventListener(ContextRefreshedEvent.class)
+ public void logPlugins() {
+ executorPlugins.forEach(p ->
+ logger.info("Loaded executor plugin '{}' version '{}'",
+ p.getName(), p.getClass().getPackage().getImplementationVersion()));
+ listenerPlugins.forEach(p ->
+ logger.info("Loaded listener plugin '{}' version '{}'",
+ p.getName(), p.getClass().getPackage().getImplementationVersion()));
+ }
- notification = GaswNotification.getInstance();
+ @PreDestroy
+ public void terminate() throws GaswException {
+ terminate(false);
+ }
- } catch (IllegalArgumentException ex) {
- throw new GaswException(ex);
+ public void terminate(boolean force) throws GaswException {
+ gaswNotification.terminate();
+ for (ExecutorPlugin executorPlugin : executorPlugins) {
+ executorPlugin.terminate(force);
}
- }
- public synchronized void setNotificationClient(Object client) {
- notification.setClient(client);
+ for (ListenerPlugin listenerPlugin : listenerPlugins) {
+ listenerPlugin.terminate();
+ }
}
- public synchronized String submit(GaswInput gaswInput) throws GaswException {
-
- ExecutorPlugin executor = ExecutorFactory.getExecutor(gaswInput);
- executor.load(gaswInput);
- return executor.submit();
+ public void setNotificationClient(Object client) {
+ gaswNotification.setNotificationClient(client);
}
- public synchronized List getFinishedJobs() {
- return notification.getFinishedJobs();
+ public String submit(GaswInput gaswInput) throws GaswException {
+ return executorFactory.getExecutor().submit(gaswInput);
}
- public synchronized void waitForNotification() {
- notification.waitForNotification();
+ public List getFinishedJobs() {
+ return gaswNotification.getFinishedJobs();
}
- public synchronized void terminate(boolean force) throws GaswException {
- notification.terminate();
+ private void loadSEEntryPoints() throws GaswException {
+ try {
+ logger.info("Loading SEs entry points.");
+ ProcessBuilder builder = new ProcessBuilder("lcg-info", "--list-service",
+ "--vo", config.getVoName(), "--attrs", "ServiceEndpoint");
+
+ builder.redirectErrorStream(true);
+ Process process = builder.start();
+
+ BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ String s = null;
+ StringBuilder cout = new StringBuilder();
+
+ while ((s = r.readLine()) != null) {
+ cout.append(s);
+ if (s.startsWith("- Service: httpg://")) {
+ try {
+ URI service = new URI(s.split(" ")[2]);
+ seEntryPointsDAO.add(
+ new SEEntryPoint(new SEEntryPointID(
+ service.getHost(), service.getPort()),
+ service.getPath()));
+
+ } catch (URISyntaxException ex) {
+ logger.warn("Unable to read end point from: {}", s);
+ } catch (DAOException ex) {
+ if (!ex.getMessage().contains("duplicate key value")) {
+ logger.warn("Unable to save end point: {}", ex.getMessage());
+ }
+ }
+ }
+ }
+ r.close();
+ process.waitFor();
+
+ if (process.exitValue() != 0) {
+ logger.error(cout.toString());
+ throw new GaswException("Unable to load SEs entry points.");
+ }
+ } catch (InterruptedException ex) {
+ logger.error("Error:", ex);
+ throw new GaswException(ex);
- if (GaswConfiguration.getInstance().isFailOverEnabled()) {
- FailOver.getInstance().terminate();
+ } catch (IOException ex) {
+ logger.error("Error:", ex);
+ throw new GaswException(ex);
}
-
- GaswConfiguration.getInstance().terminate(force);
}
}
diff --git a/src/main/java/fr/insalyon/creatis/gasw/GaswConfiguration.java b/src/main/java/fr/insalyon/creatis/gasw/GaswConfiguration.java
index 68f7442d..b1822823 100644
--- a/src/main/java/fr/insalyon/creatis/gasw/GaswConfiguration.java
+++ b/src/main/java/fr/insalyon/creatis/gasw/GaswConfiguration.java
@@ -32,362 +32,83 @@
*/
package fr.insalyon.creatis.gasw;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.List;
-import org.apache.commons.configuration.ConfigurationException;
-import org.apache.commons.configuration.PropertiesConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.hibernate.SessionFactory;
-import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.service.ServiceRegistry;
-
-import fr.insalyon.creatis.gasw.bean.Data;
-import fr.insalyon.creatis.gasw.bean.DataToReplicate;
-import fr.insalyon.creatis.gasw.bean.Job;
-import fr.insalyon.creatis.gasw.bean.JobMinorStatus;
-import fr.insalyon.creatis.gasw.bean.Node;
-import fr.insalyon.creatis.gasw.bean.NodeID;
-import fr.insalyon.creatis.gasw.bean.SEEntryPoint;
-import fr.insalyon.creatis.gasw.bean.SEEntryPointID;
-import fr.insalyon.creatis.gasw.dao.DAOException;
-import fr.insalyon.creatis.gasw.dao.DAOFactory;
-import fr.insalyon.creatis.gasw.plugin.DatabasePlugin;
-import fr.insalyon.creatis.gasw.plugin.ExecutorPlugin;
-import fr.insalyon.creatis.gasw.plugin.ListenerPlugin;
-import net.xeoh.plugins.base.PluginManager;
-import net.xeoh.plugins.base.impl.PluginManagerFactory;
-import net.xeoh.plugins.base.util.JSPFProperties;
-import net.xeoh.plugins.base.util.PluginManagerUtil;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.beans.factory.annotation.Value;
+@Configuration
+@PropertySource("classpath:gasw.properties")
public class GaswConfiguration {
-
- private static final Logger logger = LoggerFactory.getLogger(GaswConfiguration.class);
- private static final String configDir = "./conf";
- private static final String configFile = "settings.conf";
- private static GaswConfiguration instance;
- private static boolean strict = true;
- private PropertiesConfiguration config;
- private PluginManager pm;
- // Properties
- private String executionPath;
- private String simulationID;
+ // Final properties
+ private final String executionPath = new File("").getAbsolutePath();
+ private final String simulationID = executionPath.substring(executionPath.lastIndexOf("/") + 1);
// Default Properties
+ @Value("${gasw.default.executor}")
private String defaultExecutor;
+ @Value("${gasw.default.environment}")
private String defaultEnvironment;
+ @Value("${gasw.default.background-script}")
private String defaultBackgroundScript;
+ @Value("${gasw.default.requirements}")
private String defaultRequirements;
+ @Value("${gasw.default.retry-count}")
private int defaultRetryCount;
+ @Value("${gasw.default.timeout}")
private int defaultTimeout;
- private int defaultSleeptime;
+ @Value("${gasw.default.sleep-time}")
+ private int defaultSleeptimeSeconds;
+ @Value("${gasw.default.cpu-time}")
private int defaultCPUTime;
// Virtual Organization
+ @Value("${gasw.vo.name}")
private String voName;
+ @Value("${gasw.vo.default-SE}")
private String voDefaultSE;
+ @Value("${gasw.vo.use-close-SE}")
private String voUseCloseSE;
// Boutiques installation
+ @Value("${gasw.boutiques.bosh-CVMFS-path}")
private String boshCVMFSPath;
- private String singularityPath;
- private String containersCVMFSPath;
- private String udockerTag;
- private String boutiquesProvenanceDir;
+ @Value("${gasw.boutiques.file-name}")
private String boutiquesFileName;
+ @Value("${gasw.boutiques.provenance-dir}")
+ private String boutiquesProvenanceDir;
// Containers stuff
+ @Value("${gasw.containers.runtime}")
private String containersRuntime;
+ @Value("${gasw.containers.images-base-path}")
private String containersImagesBasePath;
+ @Value("${gasw.containers.singularity-path}")
+ private String singularityPath;
+ @Value("${gasw.containers.CVMFS-path}")
+ private String containersCVMFSPath;
+ @Value("${gasw.containers.udocker-tag}")
+ private String udockerTag;
// Failover Server
+ @Value("${gasw.failover.enabled}")
private boolean failOverEnabled;
+ @Value("${gasw.failover.host}")
private String failOverHost;
+ @Value("${gasw.failover.port}")
private int failOverPort;
+ @Value("${gasw.failover.home}")
private String failOverHome;
+ @Value("${gasw.failover.max-retry}")
private int failOverMaxRetry;
//MIN_AVG_DOWNLOAD_THROUGHPUT for the lcg-c* SEND_RECEIVE_TIMEOUT
+ @Value("${gasw.download.min-avg-throughput}")
private int minAvgDownloadThroughput;
// Minor Status Service
+ @Value("${gasw.minor-status.enabled}")
private boolean minorStatusEnabled;
// Others
+ @Value("${gasw.source.script}")
private String sourceScript;
- // Plugins
- private List