This is an automated email from the ASF dual-hosted git repository. yasith pushed a commit to branch worktree-reliability+server-hardening in repository https://gitbox.apache.org/repos/asf/airavata.git
commit e22676719df381e9d3b68130fb5afd00757ba4a6 Author: yasithdev <[email protected]> AuthorDate: Mon Mar 30 12:05:36 2026 -0400 refactor: switch to Spring Boot auto-configured JPA, remove manual EntityManagerFactory Replace the manual LocalContainerEntityManagerFactoryBean with Spring Boot's auto-configured JPA using @EntityScan("org.apache.airavata") and PhysicalNamingStrategyStandardImpl (set via application.yml). This resolves the Hibernate 6.6 DuplicateMappingException by ensuring @Column and @JoinColumn annotations use consistent logical names. Also fix SpringSettingsBridge ordering: use constructor injection + @DependsOn on AiravataServerHandler to ensure JDBC overrides are registered before any bean reads airavata.jdbc.* properties. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --- .../airavata/common/db/SpringSettingsBridge.java | 27 ++++++---------- .../apache/airavata/server/AiravataServerMain.java | 36 ++-------------------- airavata-server/src/main/resources/application.yml | 5 +++ .../thrift/handler/AiravataServerHandler.java | 1 + 4 files changed, 19 insertions(+), 50 deletions(-) diff --git a/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java b/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java index 1c7964ea46..e2d36389e7 100644 --- a/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java +++ b/airavata-api/src/main/java/org/apache/airavata/common/db/SpringSettingsBridge.java @@ -19,34 +19,27 @@ */ package org.apache.airavata.common.db; -import jakarta.annotation.PostConstruct; import org.apache.airavata.common.config.ApplicationSettings; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * Bridges Spring datasource configuration into {@link ApplicationSettings} so that legacy code * reading {@code airavata.jdbc.*} transparently receives the same values as - * {@code spring.datasource.*}. This eliminates the need to duplicate JDBC credentials in - * {@code airavata-server.properties}. + * {@code spring.datasource.*}. Runs in the constructor (not @PostConstruct) to ensure values + * are available before any other bean reads them. */ @Component +@Order(Ordered.HIGHEST_PRECEDENCE) public class SpringSettingsBridge { - @Value("${spring.datasource.url}") - private String url; - - @Value("${spring.datasource.username}") - private String username; - - @Value("${spring.datasource.password}") - private String password; - - @Value("${spring.datasource.driver-class-name}") - private String driverClassName; - - @PostConstruct - public void bridge() { + public SpringSettingsBridge( + @Value("${spring.datasource.url}") String url, + @Value("${spring.datasource.username}") String username, + @Value("${spring.datasource.password}") String password, + @Value("${spring.datasource.driver-class-name}") String driverClassName) { ApplicationSettings.setOverride("airavata.jdbc.url", url); ApplicationSettings.setOverride("airavata.jdbc.user", username); ApplicationSettings.setOverride("airavata.jdbc.password", password); diff --git a/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java b/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java index 11d7bdcfe8..509a7159b5 100644 --- a/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java +++ b/airavata-server/src/main/java/org/apache/airavata/server/AiravataServerMain.java @@ -19,52 +19,22 @@ */ package org.apache.airavata.server; -import javax.sql.DataSource; - import org.apache.airavata.common.config.AiravataServerProperties; import org.apache.airavata.server.grpc.AiravataGrpcServerConfig; import org.apache.airavata.server.rest.AiravataRestServerConfig; import org.apache.airavata.server.thrift.AiravataThriftServerConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -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 jakarta.persistence.EntityManagerFactory; -@SpringBootApplication( - scanBasePackages = {"org.apache.airavata.server", "org.apache.airavata.common.db"}, - exclude = {HibernateJpaAutoConfiguration.class} -) +@SpringBootApplication(scanBasePackages = {"org.apache.airavata.server", "org.apache.airavata.common.db"}) +@EntityScan("org.apache.airavata") @EnableConfigurationProperties(AiravataServerProperties.class) @Import({AiravataRestServerConfig.class, AiravataGrpcServerConfig.class, AiravataThriftServerConfig.class}) public class AiravataServerMain { public static void main(String[] args) { SpringApplication.run(AiravataServerMain.class, args); } - - @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { - var em = new LocalContainerEntityManagerFactoryBean(); - em.setDataSource(dataSource); - // Scan all entity packages instead of using persistence.xml - em.setPackagesToScan("org.apache.airavata"); - em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); - em.getJpaPropertyMap().put("hibernate.hbm2ddl.auto", "none"); - em.getJpaPropertyMap().put("hibernate.enable_lazy_load_no_trans", "true"); - em.getJpaPropertyMap().put("hibernate.physical_naming_strategy", - "org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl"); - return em; - } - - @Bean - public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { - return new JpaTransactionManager(emf); - } } diff --git a/airavata-server/src/main/resources/application.yml b/airavata-server/src/main/resources/application.yml index 57f4b02c6e..a72bb11820 100644 --- a/airavata-server/src/main/resources/application.yml +++ b/airavata-server/src/main/resources/application.yml @@ -16,7 +16,12 @@ spring: jpa: hibernate: ddl-auto: none + naming: + physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl open-in-view: false + properties: + hibernate: + enable_lazy_load_no_trans: true servlet: multipart: max-file-size: 200MB diff --git a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java index 02a7b3bb55..2854ec67c1 100644 --- a/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java +++ b/airavata-server/thrift/src/main/java/org/apache/airavata/server/thrift/handler/AiravataServerHandler.java @@ -97,6 +97,7 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component [email protected]("springSettingsBridge") public class AiravataServerHandler implements Airavata.Iface { private static final Logger logger = LoggerFactory.getLogger(AiravataServerHandler.class); private Publisher statusPublisher;
