This is an automated email from the ASF dual-hosted git repository.

yasith pushed a commit to branch service-layer-improvements
in repository https://gitbox.apache.org/repos/asf/airavata.git


The following commit(s) were added to refs/heads/service-layer-improvements by 
this push:
     new c5b9462008 fix entity issues preventing airavata-api from working in 
spring
c5b9462008 is described below

commit c5b94620080d5dd9500758310057c10f54ea1c53
Author: yasithdev <[email protected]>
AuthorDate: Fri Dec 12 12:40:29 2025 -0600

    fix entity issues preventing airavata-api from working in spring
---
 .../entities/appcatalog/BatchQueueEntity.java      |   2 +-
 .../entities/appcatalog/ComputeResourceEntity.java |   3 +
 .../ComputeResourceFileSystemEntity.java           |   2 +-
 .../appcatalog/DataMovementInterfaceEntity.java    |   2 +-
 .../appcatalog/JobManagerCommandEntity.java        |   2 +-
 .../appcatalog/JobSubmissionInterfaceEntity.java   |   2 +-
 .../appcatalog/ParallelismCommandEntity.java       |   2 +-
 .../appcatalog/StorageInterfaceEntity.java         |   2 +-
 .../appcatalog/StoragePreferenceEntity.java        |   2 +-
 .../entities/expcatalog/ExperimentEntity.java      |   5 +
 .../registry/services/ComputeResourceService.java  | 172 +++++++++++++++++----
 .../registry/services/ExperimentService.java       |  57 +++++--
 .../airavata/registry/services/GatewayService.java |   2 +-
 .../airavata/registry/services/ProjectService.java |   2 +-
 .../registry/services/StorageResourceService.java  |  11 +-
 .../airavata/registry/utils/AppCatalogUtils.java   |  25 +--
 .../expcatalog/ExperimentRepositoryTest.java       |   3 +-
 17 files changed, 224 insertions(+), 72 deletions(-)

diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/BatchQueueEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/BatchQueueEntity.java
index bae5b384f2..30d2117e11 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/BatchQueueEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/BatchQueueEntity.java
@@ -58,7 +58,7 @@ public class BatchQueueEntity implements Serializable {
     private String queueDescription;
 
     @ManyToOne(targetEntity = ComputeResourceEntity.class, cascade = 
CascadeType.MERGE)
-    @JoinColumn(name = "COMPUTE_RESOURCE_ID")
+    @JoinColumn(name = "COMPUTE_RESOURCE_ID", insertable = false, updatable = 
false)
     private ComputeResourceEntity computeResource;
 
     @Column(name = "CPU_PER_NODE")
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceEntity.java
index e1133311c4..e192b39c00 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceEntity.java
@@ -89,6 +89,7 @@ public class ComputeResourceEntity implements Serializable {
             targetEntity = BatchQueueEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "computeResource",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<BatchQueueEntity> batchQueues;
 
@@ -96,6 +97,7 @@ public class ComputeResourceEntity implements Serializable {
             targetEntity = JobSubmissionInterfaceEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "computeResource",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<JobSubmissionInterfaceEntity> jobSubmissionInterfaces;
 
@@ -103,6 +105,7 @@ public class ComputeResourceEntity implements Serializable {
             targetEntity = DataMovementInterfaceEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "computeResource",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<DataMovementInterfaceEntity> dataMovementInterfaces;
 
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceFileSystemEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceFileSystemEntity.java
index ec6f6396ec..ef967b010c 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceFileSystemEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ComputeResourceFileSystemEntity.java
@@ -43,7 +43,7 @@ public class ComputeResourceFileSystemEntity implements 
Serializable {
     private FileSystems fileSystem;
 
     @ManyToOne(cascade = CascadeType.MERGE)
-    @JoinColumn(name = "COMPUTE_RESOURCE_ID")
+    @JoinColumn(name = "COMPUTE_RESOURCE_ID", insertable = false, updatable = 
false)
     private ComputeResourceEntity computeResource;
 
     @Column(name = "PATH")
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/DataMovementInterfaceEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/DataMovementInterfaceEntity.java
index 12fabd54f1..16bc4eb620 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/DataMovementInterfaceEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/DataMovementInterfaceEntity.java
@@ -55,7 +55,7 @@ public class DataMovementInterfaceEntity implements 
Serializable {
     private Timestamp updateTime;
 
     @ManyToOne(targetEntity = ComputeResourceEntity.class)
-    @JoinColumn(name = "COMPUTE_RESOURCE_ID", nullable = false, updatable = 
false)
+    @JoinColumn(name = "COMPUTE_RESOURCE_ID", insertable = false, updatable = 
false)
     private ComputeResourceEntity computeResource;
 
     public DataMovementInterfaceEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobManagerCommandEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobManagerCommandEntity.java
index d2aa3eacbb..9e15d1c406 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobManagerCommandEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobManagerCommandEntity.java
@@ -45,7 +45,7 @@ public class JobManagerCommandEntity implements Serializable {
     private String command;
 
     @ManyToOne(cascade = CascadeType.MERGE)
-    @JoinColumn(name = "RESOURCE_JOB_MANAGER_ID")
+    @JoinColumn(name = "RESOURCE_JOB_MANAGER_ID", insertable = false, 
updatable = false)
     private ResourceJobManagerEntity resourceJobManager;
 
     public JobManagerCommandEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobSubmissionInterfaceEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobSubmissionInterfaceEntity.java
index 201c0746de..83d003491f 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobSubmissionInterfaceEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/JobSubmissionInterfaceEntity.java
@@ -55,7 +55,7 @@ public class JobSubmissionInterfaceEntity implements 
Serializable {
     private Timestamp updateTime;
 
     @ManyToOne(targetEntity = ComputeResourceEntity.class)
-    @JoinColumn(name = "COMPUTE_RESOURCE_ID", nullable = false, updatable = 
false)
+    @JoinColumn(name = "COMPUTE_RESOURCE_ID", insertable = false, updatable = 
false)
     private ComputeResourceEntity computeResource;
 
     public JobSubmissionInterfaceEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ParallelismCommandEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ParallelismCommandEntity.java
index 3f57e77bd5..4d01e6dc78 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ParallelismCommandEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/ParallelismCommandEntity.java
@@ -45,7 +45,7 @@ public class ParallelismCommandEntity implements Serializable 
{
     private String command;
 
     @ManyToOne(cascade = CascadeType.MERGE)
-    @JoinColumn(name = "RESOURCE_JOB_MANAGER_ID")
+    @JoinColumn(name = "RESOURCE_JOB_MANAGER_ID", insertable = false, 
updatable = false)
     private ResourceJobManagerEntity resourceJobManager;
 
     public ParallelismCommandEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StorageInterfaceEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StorageInterfaceEntity.java
index 9e5a79569d..134cebba3f 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StorageInterfaceEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StorageInterfaceEntity.java
@@ -55,7 +55,7 @@ public class StorageInterfaceEntity implements Serializable {
     private Timestamp updateTime;
 
     @ManyToOne(targetEntity = StorageResourceEntity.class, cascade = 
CascadeType.MERGE)
-    @JoinColumn(name = "STORAGE_RESOURCE_ID")
+    @JoinColumn(name = "STORAGE_RESOURCE_ID", insertable = false, updatable = 
false)
     private StorageResourceEntity storageResource;
 
     public StorageInterfaceEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StoragePreferenceEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StoragePreferenceEntity.java
index 83613b9c92..eeba16a81a 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StoragePreferenceEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/appcatalog/StoragePreferenceEntity.java
@@ -49,7 +49,7 @@ public class StoragePreferenceEntity implements Serializable {
     private String resourceSpecificCredentialStoreToken;
 
     @ManyToOne(targetEntity = GatewayProfileEntity.class, cascade = 
CascadeType.MERGE)
-    @JoinColumn(name = "GATEWAY_ID")
+    @JoinColumn(name = "GATEWAY_ID", insertable = false, updatable = false)
     private GatewayProfileEntity gatewayProfileResource;
 
     public StoragePreferenceEntity() {}
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/expcatalog/ExperimentEntity.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/expcatalog/ExperimentEntity.java
index 9bd6327892..b629b5ebda 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/entities/expcatalog/ExperimentEntity.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/entities/expcatalog/ExperimentEntity.java
@@ -91,6 +91,7 @@ public class ExperimentEntity implements Serializable {
             targetEntity = ExperimentInputEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "experiment",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<ExperimentInputEntity> experimentInputs;
 
@@ -98,6 +99,7 @@ public class ExperimentEntity implements Serializable {
             targetEntity = ExperimentOutputEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "experiment",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<ExperimentOutputEntity> experimentOutputs;
 
@@ -105,6 +107,7 @@ public class ExperimentEntity implements Serializable {
             targetEntity = ExperimentStatusEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "experiment",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     @OrderBy("timeOfStateChange ASC")
     private List<ExperimentStatusEntity> experimentStatus;
@@ -113,6 +116,7 @@ public class ExperimentEntity implements Serializable {
             targetEntity = ExperimentErrorEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "experiment",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<ExperimentErrorEntity> errors;
 
@@ -120,6 +124,7 @@ public class ExperimentEntity implements Serializable {
             targetEntity = ProcessEntity.class,
             cascade = CascadeType.ALL,
             mappedBy = "experiment",
+            orphanRemoval = true,
             fetch = FetchType.EAGER)
     private List<ProcessEntity> processes;
 
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ComputeResourceService.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ComputeResourceService.java
index 04ef76c8bb..b75c5ed6f6 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ComputeResourceService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ComputeResourceService.java
@@ -53,11 +53,13 @@ import 
org.apache.airavata.registry.entities.appcatalog.DataMovementInterfacePK;
 import 
org.apache.airavata.registry.entities.appcatalog.GridftpDataMovementEntity;
 import org.apache.airavata.registry.entities.appcatalog.GridftpEndpointEntity;
 import 
org.apache.airavata.registry.entities.appcatalog.JobManagerCommandEntity;
+import org.apache.airavata.registry.entities.appcatalog.JobManagerCommandPK;
 import 
org.apache.airavata.registry.entities.appcatalog.JobSubmissionInterfaceEntity;
 import 
org.apache.airavata.registry.entities.appcatalog.JobSubmissionInterfacePK;
 import 
org.apache.airavata.registry.entities.appcatalog.LocalDataMovementEntity;
 import org.apache.airavata.registry.entities.appcatalog.LocalSubmissionEntity;
 import 
org.apache.airavata.registry.entities.appcatalog.ParallelismCommandEntity;
+import org.apache.airavata.registry.entities.appcatalog.ParallelismCommandPK;
 import 
org.apache.airavata.registry.entities.appcatalog.ResourceJobManagerEntity;
 import org.apache.airavata.registry.entities.appcatalog.ScpDataMovementEntity;
 import org.apache.airavata.registry.entities.appcatalog.SshJobSubmissionEntity;
@@ -173,7 +175,23 @@ public class ComputeResourceService {
     private ComputeResourceEntity 
saveComputeResource(ComputeResourceDescription description)
             throws AppCatalogException {
         String computeResourceId = description.getComputeResourceId();
-        ComputeResourceEntity computeResourceEntity = mapper.map(description, 
ComputeResourceEntity.class);
+        
+        ComputeResourceEntity existingEntity = 
computeResourceRepository.findById(computeResourceId).orElse(null);
+        ComputeResourceEntity computeResourceEntity;
+        
+        if (existingEntity != null) {
+            ComputeResourceEntity newEntity = mapper.map(description, 
ComputeResourceEntity.class);
+            mapper.map(description, existingEntity);
+            
+            mergeLists(existingEntity.getBatchQueues(), 
newEntity.getBatchQueues(), 
org.apache.airavata.registry.entities.appcatalog.BatchQueueEntity::getQueueName);
+            mergeLists(existingEntity.getDataMovementInterfaces(), 
newEntity.getDataMovementInterfaces(), 
org.apache.airavata.registry.entities.appcatalog.DataMovementInterfaceEntity::getDataMovementInterfaceId);
+            mergeLists(existingEntity.getJobSubmissionInterfaces(), 
newEntity.getJobSubmissionInterfaces(), 
org.apache.airavata.registry.entities.appcatalog.JobSubmissionInterfaceEntity::getJobSubmissionInterfaceId);
+            
+            computeResourceEntity = existingEntity;
+        } else {
+            computeResourceEntity = mapper.map(description, 
ComputeResourceEntity.class);
+        }
+
         if (computeResourceEntity.getBatchQueues() != null) {
             computeResourceEntity
                     .getBatchQueues()
@@ -297,8 +315,13 @@ public class ComputeResourceService {
         String submissionId = AppCatalogUtils.getID("SSH");
         sshJobSubmission.setJobSubmissionInterfaceId(submissionId);
         String resourceJobManagerId = 
addResourceJobManager(sshJobSubmission.getResourceJobManager());
+        
+        ResourceJobManagerEntity resourceJobManagerEntity = 
resourceJobManagerRepository.findById(resourceJobManagerId)
+                .orElseThrow(() -> new AppCatalogException("ResourceJobManager 
not found: " + resourceJobManagerId));
+
         SshJobSubmissionEntity sshJobSubmissionEntity = 
mapper.map(sshJobSubmission, SshJobSubmissionEntity.class);
-        
sshJobSubmissionEntity.getResourceJobManager().setResourceJobManagerId(resourceJobManagerId);
+        sshJobSubmissionEntity.setResourceJobManager(resourceJobManagerEntity);
+        
         if (sshJobSubmission.getResourceJobManager().getParallelismPrefix() != 
null) {
             createParallesimPrefix(
                     
sshJobSubmission.getResourceJobManager().getParallelismPrefix(),
@@ -318,7 +341,14 @@ public class ComputeResourceService {
     }
 
     public void updateSSHJobSubmission(SSHJobSubmission sshJobSubmission) 
throws AppCatalogException {
-        SshJobSubmissionEntity sshJobSubmissionEntity = 
mapper.map(sshJobSubmission, SshJobSubmissionEntity.class);
+        SshJobSubmissionEntity existingEntity = 
sshJobSubmissionRepository.findById(sshJobSubmission.getJobSubmissionInterfaceId()).orElse(null);
+        SshJobSubmissionEntity sshJobSubmissionEntity;
+        if (existingEntity != null) {
+            mapper.map(sshJobSubmission, existingEntity);
+            sshJobSubmissionEntity = existingEntity;
+        } else {
+            sshJobSubmissionEntity = mapper.map(sshJobSubmission, 
SshJobSubmissionEntity.class);
+        }
         
sshJobSubmissionEntity.setUpdateTime(AiravataUtils.getCurrentTimestamp());
         sshJobSubmissionRepository.save(sshJobSubmissionEntity);
     }
@@ -332,8 +362,14 @@ public class ComputeResourceService {
     }
 
     public void updateCloudJobSubmission(CloudJobSubmission 
cloudJobSubmission) throws AppCatalogException {
-        CloudJobSubmissionEntity cloudJobSubmissionEntity =
-                mapper.map(cloudJobSubmission, CloudJobSubmissionEntity.class);
+        CloudJobSubmissionEntity existingEntity = 
cloudJobSubmissionRepository.findById(cloudJobSubmission.getJobSubmissionInterfaceId()).orElse(null);
+        CloudJobSubmissionEntity cloudJobSubmissionEntity;
+        if (existingEntity != null) {
+            mapper.map(cloudJobSubmission, existingEntity);
+            cloudJobSubmissionEntity = existingEntity;
+        } else {
+            cloudJobSubmissionEntity = mapper.map(cloudJobSubmission, 
CloudJobSubmissionEntity.class);
+        }
         cloudJobSubmissionRepository.save(cloudJobSubmissionEntity);
     }
 
@@ -357,8 +393,16 @@ public class ComputeResourceService {
     public void updateResourceJobManager(String resourceJobManagerId, 
ResourceJobManager updatedResourceJobManager)
             throws AppCatalogException {
         
updatedResourceJobManager.setResourceJobManagerId(resourceJobManagerId);
-        ResourceJobManagerEntity resourceJobManagerEntity =
-                mapper.map(updatedResourceJobManager, 
ResourceJobManagerEntity.class);
+        
+        ResourceJobManagerEntity existingEntity = 
resourceJobManagerRepository.findById(resourceJobManagerId).orElse(null);
+        ResourceJobManagerEntity resourceJobManagerEntity;
+        if (existingEntity != null) {
+            mapper.map(updatedResourceJobManager, existingEntity);
+            resourceJobManagerEntity = existingEntity;
+        } else {
+            resourceJobManagerEntity = mapper.map(updatedResourceJobManager, 
ResourceJobManagerEntity.class);
+        }
+        
         resourceJobManagerEntity = 
resourceJobManagerRepository.save(resourceJobManagerEntity);
         Map<JobManagerCommand, String> jobManagerCommands = 
updatedResourceJobManager.getJobManagerCommands();
         if (jobManagerCommands != null && jobManagerCommands.size() != 0) {
@@ -393,9 +437,14 @@ public class ComputeResourceService {
     public String addLocalJobSubmission(LOCALSubmission localSubmission) 
throws AppCatalogException {
         
localSubmission.setJobSubmissionInterfaceId(AppCatalogUtils.getID("LOCAL"));
         String resourceJobManagerId = 
addResourceJobManager(localSubmission.getResourceJobManager());
+        
+        ResourceJobManagerEntity resourceJobManagerEntity = 
resourceJobManagerRepository.findById(resourceJobManagerId)
+                .orElseThrow(() -> new AppCatalogException("ResourceJobManager 
not found: " + resourceJobManagerId));
+
         LocalSubmissionEntity localSubmissionEntity = 
mapper.map(localSubmission, LocalSubmissionEntity.class);
         localSubmissionEntity.setResourceJobManagerId(resourceJobManagerId);
-        
localSubmissionEntity.getResourceJobManager().setResourceJobManagerId(resourceJobManagerId);
+        localSubmissionEntity.setResourceJobManager(resourceJobManagerEntity);
+        
         if (localSubmission.getResourceJobManager().getParallelismPrefix() != 
null) {
             createParallesimPrefix(
                     
localSubmission.getResourceJobManager().getParallelismPrefix(),
@@ -413,7 +462,14 @@ public class ComputeResourceService {
     }
 
     public void updateLocalJobSubmission(LOCALSubmission localSubmission) 
throws AppCatalogException {
-        LocalSubmissionEntity localSubmissionEntity = 
mapper.map(localSubmission, LocalSubmissionEntity.class);
+        LocalSubmissionEntity existingEntity = 
localSubmissionRepository.findById(localSubmission.getJobSubmissionInterfaceId()).orElse(null);
+        LocalSubmissionEntity localSubmissionEntity;
+        if (existingEntity != null) {
+            mapper.map(localSubmission, existingEntity);
+            localSubmissionEntity = existingEntity;
+        } else {
+            localSubmissionEntity = mapper.map(localSubmission, 
LocalSubmissionEntity.class);
+        }
         
localSubmissionEntity.setUpdateTime(AiravataUtils.getCurrentTimestamp());
         localSubmissionRepository.save(localSubmissionEntity);
     }
@@ -434,8 +490,15 @@ public class ComputeResourceService {
     }
 
     public void updateUNICOREJobSubmission(UnicoreJobSubmission 
unicoreJobSubmission) throws AppCatalogException {
-        UnicoreSubmissionEntity unicoreSubmissionEntity =
-                mapper.map(unicoreJobSubmission, 
UnicoreSubmissionEntity.class);
+        UnicoreSubmissionEntity existingEntity = 
unicoreSubmissionRepository.findById(unicoreJobSubmission.getJobSubmissionInterfaceId()).orElse(null);
+        UnicoreSubmissionEntity unicoreSubmissionEntity;
+        if (existingEntity != null) {
+            mapper.map(unicoreJobSubmission, existingEntity);
+            unicoreSubmissionEntity = existingEntity;
+        } else {
+            unicoreSubmissionEntity = mapper.map(unicoreJobSubmission, 
UnicoreSubmissionEntity.class);
+        }
+        
         if (unicoreJobSubmission.getSecurityProtocol() != null) {
             
unicoreSubmissionEntity.setSecurityProtocol(unicoreJobSubmission.getSecurityProtocol());
         }
@@ -450,7 +513,14 @@ public class ComputeResourceService {
     }
 
     public void updateLocalDataMovement(LOCALDataMovement localDataMovement) 
throws AppCatalogException {
-        LocalDataMovementEntity localDataMovementEntity = 
mapper.map(localDataMovement, LocalDataMovementEntity.class);
+        LocalDataMovementEntity existingEntity = 
localDataMovementRepository.findById(localDataMovement.getDataMovementInterfaceId()).orElse(null);
+        LocalDataMovementEntity localDataMovementEntity;
+        if (existingEntity != null) {
+            mapper.map(localDataMovement, existingEntity);
+            localDataMovementEntity = existingEntity;
+        } else {
+            localDataMovementEntity = mapper.map(localDataMovement, 
LocalDataMovementEntity.class);
+        }
         localDataMovementRepository.save(localDataMovementEntity);
     }
 
@@ -462,7 +532,14 @@ public class ComputeResourceService {
     }
 
     public void updateScpDataMovement(SCPDataMovement scpDataMovement) throws 
AppCatalogException {
-        ScpDataMovementEntity scpDataMovementEntity = 
mapper.map(scpDataMovement, ScpDataMovementEntity.class);
+        ScpDataMovementEntity existingEntity = 
scpDataMovementRepository.findById(scpDataMovement.getDataMovementInterfaceId()).orElse(null);
+        ScpDataMovementEntity scpDataMovementEntity;
+        if (existingEntity != null) {
+            mapper.map(scpDataMovement, existingEntity);
+            scpDataMovementEntity = existingEntity;
+        } else {
+            scpDataMovementEntity = mapper.map(scpDataMovement, 
ScpDataMovementEntity.class);
+        }
         
scpDataMovementEntity.setUpdateTime(AiravataUtils.getCurrentTimestamp());
         scpDataMovementRepository.save(scpDataMovementEntity);
     }
@@ -563,25 +640,30 @@ public class ComputeResourceService {
 
     public void removeJobSubmissionInterface(String computeResourceId, String 
jobSubmissionInterfaceId)
             throws AppCatalogException {
-        JobSubmissionInterfacePK jobSubmissionInterfacePK = new 
JobSubmissionInterfacePK();
-        jobSubmissionInterfacePK.setComputeResourceId(computeResourceId);
-        
jobSubmissionInterfacePK.setJobSubmissionInterfaceId(jobSubmissionInterfaceId);
-        jobSubmissionInterfaceRepository.deleteById(jobSubmissionInterfacePK);
+        ComputeResourceEntity entity = 
computeResourceRepository.findById(computeResourceId).orElse(null);
+        if (entity != null && entity.getJobSubmissionInterfaces() != null) {
+            entity.getJobSubmissionInterfaces().removeIf(iface -> 
+                
iface.getJobSubmissionInterfaceId().equals(jobSubmissionInterfaceId));
+            computeResourceRepository.save(entity);
+        }
     }
 
     public void removeDataMovementInterface(String computeResourceId, String 
dataMovementInterfaceId)
             throws AppCatalogException {
-        DataMovementInterfacePK dataMovementInterfacePK = new 
DataMovementInterfacePK();
-        
dataMovementInterfacePK.setDataMovementInterfaceId(dataMovementInterfaceId);
-        dataMovementInterfacePK.setComputeResourceId(computeResourceId);
-        dataMovementRepository.deleteById(dataMovementInterfacePK);
+        ComputeResourceEntity entity = 
computeResourceRepository.findById(computeResourceId).orElse(null);
+        if (entity != null && entity.getDataMovementInterfaces() != null) {
+            entity.getDataMovementInterfaces().removeIf(iface -> 
+                
iface.getDataMovementInterfaceId().equals(dataMovementInterfaceId));
+            computeResourceRepository.save(entity);
+        }
     }
 
     public void removeBatchQueue(String computeResourceId, String queueName) 
throws AppCatalogException {
-        BatchQueuePK batchQueuePK = new BatchQueuePK();
-        batchQueuePK.setQueueName(queueName);
-        batchQueuePK.setComputeResourceId(computeResourceId);
-        batchQueueRepository.deleteById(batchQueuePK);
+        ComputeResourceEntity entity = 
computeResourceRepository.findById(computeResourceId).orElse(null);
+        if (entity != null && entity.getBatchQueues() != null) {
+            entity.getBatchQueues().removeIf(queue -> 
queue.getQueueName().equals(queueName));
+            computeResourceRepository.save(entity);
+        }
     }
 
     public LOCALSubmission getLocalJobSubmission(String submissionId) throws 
AppCatalogException {
@@ -616,11 +698,16 @@ public class ComputeResourceService {
         }
         String resourceJobManagerId = 
resourceJobManagerEntity.getResourceJobManagerId();
         for (Map.Entry<ApplicationParallelismType, String> entry : 
parallelismPrefix.entrySet()) {
-            ParallelismCommandEntity entity = new ParallelismCommandEntity();
+            ParallelismCommandPK pk = new ParallelismCommandPK();
+            pk.setResourceJobManagerId(resourceJobManagerId);
+            pk.setCommandType(entry.getKey());
+            
+            ParallelismCommandEntity entity = 
parallelismCommandRepository.findById(pk).orElse(new 
ParallelismCommandEntity());
+            
             entity.setResourceJobManagerId(resourceJobManagerId);
             entity.setCommandType(entry.getKey());
             entity.setCommand(entry.getValue());
-            entity.setResourceJobManager(resourceJobManagerEntity);
+            // entity.setResourceJobManager(resourceJobManagerEntity); // 
Avoid setting relationship to prevent unmanaged object exception
             parallelismCommandRepository.save(entity);
         }
     }
@@ -632,11 +719,16 @@ public class ComputeResourceService {
         }
         String resourceJobManagerId = 
resourceJobManagerEntity.getResourceJobManagerId();
         for (Map.Entry<JobManagerCommand, String> entry : 
jobManagerCommands.entrySet()) {
-            JobManagerCommandEntity entity = new JobManagerCommandEntity();
+            JobManagerCommandPK pk = new JobManagerCommandPK();
+            pk.setResourceJobManagerId(resourceJobManagerId);
+            pk.setCommandType(entry.getKey());
+            
+            JobManagerCommandEntity entity = 
jobManagerCommandRepository.findById(pk).orElse(new JobManagerCommandEntity());
+            
             entity.setResourceJobManagerId(resourceJobManagerId);
             entity.setCommandType(entry.getKey());
             entity.setCommand(entry.getValue());
-            entity.setResourceJobManager(resourceJobManagerEntity);
+            // entity.setResourceJobManager(resourceJobManagerEntity); // 
Avoid setting relationship to prevent unmanaged object exception
             jobManagerCommandRepository.save(entity);
         }
     }
@@ -676,4 +768,26 @@ public class ComputeResourceService {
         DataMovementInterfaceEntity saved = 
dataMovementRepository.save(entity);
         return saved.getDataMovementInterfaceId();
     }
+
+    private <T> void mergeLists(List<T> currentList, List<T> newList, 
java.util.function.Function<T, String> idExtractor) {
+        if (currentList == null || newList == null) return;
+        
+        java.util.Map<String, T> currentMap = currentList.stream()
+            .collect(java.util.stream.Collectors.toMap(idExtractor, 
java.util.function.Function.identity()));
+        
+        java.util.List<T> result = new java.util.ArrayList<>();
+        for (T newItem : newList) {
+            String id = idExtractor.apply(newItem);
+            if (id != null && currentMap.containsKey(id)) {
+                T existing = currentMap.get(id);
+                mapper.map(newItem, existing);
+                result.add(existing);
+            } else {
+                result.add(newItem);
+            }
+        }
+        
+        currentList.clear();
+        currentList.addAll(result);
+    }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentService.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentService.java
index 9242e0fe98..2b8e00b58e 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentService.java
@@ -39,6 +39,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 @Service
+@Transactional("expCatalogTransactionManager")
 public class ExperimentService {
     private static final Logger logger = 
LoggerFactory.getLogger(ExperimentService.class);
 
@@ -52,7 +53,7 @@ public class ExperimentService {
         this.mapper = mapper;
     }
 
-    @Transactional
+    @Transactional("expCatalogTransactionManager")
     public String addExperiment(ExperimentModel experimentModel) throws 
RegistryException {
         ExperimentStatus experimentStatus = new ExperimentStatus();
         experimentStatus.setState(ExperimentState.CREATED);
@@ -66,7 +67,7 @@ public class ExperimentService {
         return saveExperimentModelData(experimentModel);
     }
 
-    @Transactional
+    @Transactional("expCatalogTransactionManager")
     public void updateExperiment(ExperimentModel updatedExperimentModel, 
String experimentId) throws RegistryException {
         saveExperimentModelData(updatedExperimentModel);
     }
@@ -78,7 +79,7 @@ public class ExperimentService {
         return mapper.map(entity, ExperimentModel.class);
     }
 
-    @Transactional
+    @Transactional("expCatalogTransactionManager")
     public String addUserConfigurationData(UserConfigurationDataModel 
userConfigurationDataModel, String experimentId)
             throws RegistryException {
         ExperimentModel experimentModel = getExperiment(experimentId);
@@ -87,20 +88,20 @@ public class ExperimentService {
         return experimentId;
     }
 
-    @Transactional
+    @Transactional("expCatalogTransactionManager")
     public String updateUserConfigurationData(
             UserConfigurationDataModel updatedUserConfigurationDataModel, 
String experimentId)
             throws RegistryException {
         return addUserConfigurationData(updatedUserConfigurationDataModel, 
experimentId);
     }
 
-    @Transactional(readOnly = true)
+    @Transactional(value = "expCatalogTransactionManager", readOnly = true)
     public UserConfigurationDataModel getUserConfigurationData(String 
experimentId) throws RegistryException {
         ExperimentModel experimentModel = getExperiment(experimentId);
         return experimentModel.getUserConfigurationData();
     }
 
-    @Transactional(readOnly = true)
+    @Transactional(value = "expCatalogTransactionManager", readOnly = true)
     public List<ExperimentModel> getExperimentList(
             String gatewayId,
             String fieldName,
@@ -132,12 +133,12 @@ public class ExperimentService {
         return experimentModelList;
     }
 
-    @Transactional(readOnly = true)
+    @Transactional(value = "expCatalogTransactionManager", readOnly = true)
     public boolean isExperimentExist(String experimentId) throws 
RegistryException {
         return experimentRepository.existsById(experimentId);
     }
 
-    @Transactional
+    @Transactional("expCatalogTransactionManager")
     public void removeExperiment(String experimentId) throws RegistryException 
{
         experimentRepository.deleteById(experimentId);
     }
@@ -169,7 +170,23 @@ public class ExperimentService {
             experimentModel.setCreationTime(System.currentTimeMillis());
         }
 
-        ExperimentEntity experimentEntity = mapper.map(experimentModel, 
ExperimentEntity.class);
+        ExperimentEntity existingEntity = 
experimentRepository.findById(experimentId).orElse(null);
+        ExperimentEntity experimentEntity;
+        
+        if (existingEntity != null) {
+            ExperimentEntity newEntity = mapper.map(experimentModel, 
ExperimentEntity.class);
+            mapper.map(experimentModel, existingEntity);
+            
+            mergeLists(existingEntity.getExperimentStatus(), 
newEntity.getExperimentStatus(), 
org.apache.airavata.registry.entities.expcatalog.ExperimentStatusEntity::getStatusId);
+            mergeLists(existingEntity.getExperimentInputs(), 
newEntity.getExperimentInputs(), 
org.apache.airavata.registry.entities.expcatalog.ExperimentInputEntity::getName);
+            mergeLists(existingEntity.getExperimentOutputs(), 
newEntity.getExperimentOutputs(), 
org.apache.airavata.registry.entities.expcatalog.ExperimentOutputEntity::getName);
+            mergeLists(existingEntity.getErrors(), newEntity.getErrors(), 
org.apache.airavata.registry.entities.expcatalog.ExperimentErrorEntity::getErrorId);
+            mergeLists(existingEntity.getProcesses(), 
newEntity.getProcesses(), 
org.apache.airavata.registry.entities.expcatalog.ProcessEntity::getProcessId);
+            
+            experimentEntity = existingEntity;
+        } else {
+            experimentEntity = mapper.map(experimentModel, 
ExperimentEntity.class);
+        }
 
         if (experimentEntity.getUserConfigurationData() != null) {
             logger.debug("Populating the Primary Key of UserConfigurationData 
object for the Experiment");
@@ -224,4 +241,26 @@ public class ExperimentService {
 
         return experimentRepository.save(experimentEntity);
     }
+
+    private <T> void mergeLists(List<T> currentList, List<T> newList, 
java.util.function.Function<T, String> idExtractor) {
+        if (currentList == null || newList == null) return;
+        
+        java.util.Map<String, T> currentMap = currentList.stream()
+            .collect(java.util.stream.Collectors.toMap(idExtractor, 
java.util.function.Function.identity()));
+        
+        java.util.List<T> result = new ArrayList<>();
+        for (T newItem : newList) {
+            String id = idExtractor.apply(newItem);
+            if (id != null && currentMap.containsKey(id)) {
+                T existing = currentMap.get(id);
+                mapper.map(newItem, existing);
+                result.add(existing);
+            } else {
+                result.add(newItem);
+            }
+        }
+        
+        currentList.clear();
+        currentList.addAll(result);
+    }
 }
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/GatewayService.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/GatewayService.java
index 63068c6255..8b49594942 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/GatewayService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/GatewayService.java
@@ -30,7 +30,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 @Service
-@Transactional
+@Transactional("profileServiceTransactionManager")
 public class GatewayService {
     private final GatewayRepository gatewayRepository;
     private final Mapper mapper;
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProjectService.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProjectService.java
index df9a3f1414..1184f22eb9 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProjectService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProjectService.java
@@ -32,7 +32,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 @Service
-@Transactional
+@Transactional("expCatalogTransactionManager")
 public class ProjectService {
     private final ProjectRepository projectRepository;
     private final Mapper mapper;
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/StorageResourceService.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/StorageResourceService.java
index 3d7cadcd46..456693fe1c 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/services/StorageResourceService.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/services/StorageResourceService.java
@@ -93,8 +93,15 @@ public class StorageResourceService {
                 updatedStorageResource.getDataMovementInterfaces().stream()
                         .forEach(dm -> 
dm.setStorageResourceId(updatedStorageResource.getStorageResourceId()));
             }
-            StorageResourceEntity entity = mapper.map(updatedStorageResource, 
StorageResourceEntity.class);
-            storageResourceRepository.save(entity);
+            
+            StorageResourceEntity existingEntity = 
storageResourceRepository.findById(storageResourceId).orElse(null);
+            if (existingEntity != null) {
+                mapper.map(updatedStorageResource, existingEntity);
+                storageResourceRepository.save(existingEntity);
+            } else {
+                StorageResourceEntity entity = 
mapper.map(updatedStorageResource, StorageResourceEntity.class);
+                storageResourceRepository.save(entity);
+            }
         } catch (Exception e) {
             logger.error(
                     "Error while updating storage resource. StorageResourceId 
: "
diff --git 
a/airavata-api/src/main/java/org/apache/airavata/registry/utils/AppCatalogUtils.java
 
b/airavata-api/src/main/java/org/apache/airavata/registry/utils/AppCatalogUtils.java
index 3cd7b2c1d6..8e43a866fd 100644
--- 
a/airavata-api/src/main/java/org/apache/airavata/registry/utils/AppCatalogUtils.java
+++ 
b/airavata-api/src/main/java/org/apache/airavata/registry/utils/AppCatalogUtils.java
@@ -1,22 +1,3 @@
-/**
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
 package org.apache.airavata.registry.utils;
 
 import java.util.UUID;
@@ -24,6 +5,8 @@ import java.util.UUID;
 public class AppCatalogUtils {
     public static String getID(String name) {
         String pro = name.replaceAll("\\s", "");
-        return pro + "_" + UUID.randomUUID();
+        String id = pro + "_" + UUID.randomUUID();
+        System.out.println("DEBUG: Generated ID for " + name + ": " + id);
+        return id;
     }
-}
+}
\ No newline at end of file
diff --git 
a/airavata-api/src/test/java/org/apache/airavata/registry/repositories/expcatalog/ExperimentRepositoryTest.java
 
b/airavata-api/src/test/java/org/apache/airavata/registry/repositories/expcatalog/ExperimentRepositoryTest.java
index b82931b465..d73c9a2a73 100644
--- 
a/airavata-api/src/test/java/org/apache/airavata/registry/repositories/expcatalog/ExperimentRepositoryTest.java
+++ 
b/airavata-api/src/test/java/org/apache/airavata/registry/repositories/expcatalog/ExperimentRepositoryTest.java
@@ -63,6 +63,7 @@ import org.springframework.test.context.TestPropertySource;
         })
 @TestPropertySource(locations = "classpath:airavata.properties")
 @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
[email protected]("expCatalogTransactionManager")
 public class ExperimentRepositoryTest extends TestBase {
 
     @Configuration
@@ -120,7 +121,7 @@ public class ExperimentRepositoryTest extends TestBase {
     @org.junit.jupiter.api.BeforeEach
     public void setUp() throws Exception {
         Gateway gateway = new Gateway();
-        gateway.setGatewayId("gateway");
+        gateway.setGatewayId("gateway-" + 
java.util.UUID.randomUUID().toString());
         gateway.setDomain("SEAGRID");
         gateway.setEmailAddress("[email protected]");
         gatewayId = gatewayService.addGateway(gateway);


Reply via email to