This is an automated email from the ASF dual-hosted git repository. yasith pushed a commit to branch feat/airavata-service-layer in repository https://gitbox.apache.org/repos/asf/airavata.git
commit ba76e73af68236149e013b0844030c0f70fa9578 Author: yasithdev <[email protected]> AuthorDate: Thu Mar 26 10:34:13 2026 -0500 feat: add ResourceService for compute, storage, job submission, and data movement Extracts all resource-related registry delegates into ResourceService covering compute resources, storage resources, job submission interfaces (LOCAL, SSH, SSHFork, Cloud, UNICORE), data movement interfaces (LOCAL, SCP, UNICORE, GridFTP), resource job managers, and batch queues. Includes 16 unit tests covering each sub-domain. --- .../airavata/service/resource/ResourceService.java | 413 +++++++++++++++++++++ .../service/resource/ResourceServiceTest.java | 211 +++++++++++ 2 files changed, 624 insertions(+) diff --git a/airavata-api/src/main/java/org/apache/airavata/service/resource/ResourceService.java b/airavata-api/src/main/java/org/apache/airavata/service/resource/ResourceService.java new file mode 100644 index 0000000000..1ffc9726f7 --- /dev/null +++ b/airavata-api/src/main/java/org/apache/airavata/service/resource/ResourceService.java @@ -0,0 +1,413 @@ +package org.apache.airavata.service.resource; + +import org.apache.airavata.model.appcatalog.computeresource.*; +import org.apache.airavata.model.appcatalog.storageresource.StorageResourceDescription; +import org.apache.airavata.model.data.movement.DMType; +import org.apache.airavata.model.data.movement.GridFTPDataMovement; +import org.apache.airavata.model.data.movement.LOCALDataMovement; +import org.apache.airavata.model.data.movement.SCPDataMovement; +import org.apache.airavata.model.data.movement.UnicoreDataMovement; +import org.apache.airavata.registry.api.service.handler.RegistryServerHandler; +import org.apache.airavata.service.exception.ServiceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class ResourceService { + + private static final Logger logger = LoggerFactory.getLogger(ResourceService.class); + + private final RegistryServerHandler registryHandler; + + public ResourceService(RegistryServerHandler registryHandler) { + this.registryHandler = registryHandler; + } + + // ------------------------------------------------------------------------- + // Compute Resources + // ------------------------------------------------------------------------- + + public String registerComputeResource(ComputeResourceDescription computeResourceDescription) + throws ServiceException { + try { + return registryHandler.registerComputeResource(computeResourceDescription); + } catch (Exception e) { + throw new ServiceException("Error while saving compute resource: " + e.getMessage(), e); + } + } + + public ComputeResourceDescription getComputeResource(String computeResourceId) throws ServiceException { + try { + return registryHandler.getComputeResource(computeResourceId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving compute resource: " + e.getMessage(), e); + } + } + + public Map<String, String> getAllComputeResourceNames() throws ServiceException { + try { + return registryHandler.getAllComputeResourceNames(); + } catch (Exception e) { + throw new ServiceException("Error while retrieving compute resource names: " + e.getMessage(), e); + } + } + + public boolean updateComputeResource(String computeResourceId, + ComputeResourceDescription computeResourceDescription) throws ServiceException { + try { + return registryHandler.updateComputeResource(computeResourceId, computeResourceDescription); + } catch (Exception e) { + throw new ServiceException("Error while updating compute resource: " + e.getMessage(), e); + } + } + + public boolean deleteComputeResource(String computeResourceId) throws ServiceException { + try { + return registryHandler.deleteComputeResource(computeResourceId); + } catch (Exception e) { + throw new ServiceException("Error while deleting compute resource: " + e.getMessage(), e); + } + } + + // ------------------------------------------------------------------------- + // Storage Resources + // ------------------------------------------------------------------------- + + public String registerStorageResource(StorageResourceDescription storageResourceDescription) + throws ServiceException { + try { + return registryHandler.registerStorageResource(storageResourceDescription); + } catch (Exception e) { + throw new ServiceException("Error while saving storage resource: " + e.getMessage(), e); + } + } + + public StorageResourceDescription getStorageResource(String storageResourceId) throws ServiceException { + try { + return registryHandler.getStorageResource(storageResourceId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving storage resource: " + e.getMessage(), e); + } + } + + public Map<String, String> getAllStorageResourceNames() throws ServiceException { + try { + return registryHandler.getAllStorageResourceNames(); + } catch (Exception e) { + throw new ServiceException("Error while retrieving storage resource names: " + e.getMessage(), e); + } + } + + public boolean updateStorageResource(String storageResourceId, + StorageResourceDescription storageResourceDescription) throws ServiceException { + try { + return registryHandler.updateStorageResource(storageResourceId, storageResourceDescription); + } catch (Exception e) { + throw new ServiceException("Error while updating storage resource: " + e.getMessage(), e); + } + } + + public boolean deleteStorageResource(String storageResourceId) throws ServiceException { + try { + return registryHandler.deleteStorageResource(storageResourceId); + } catch (Exception e) { + throw new ServiceException("Error while deleting storage resource: " + e.getMessage(), e); + } + } + + // ------------------------------------------------------------------------- + // Job Submission + // ------------------------------------------------------------------------- + + public String addLocalSubmissionDetails(String computeResourceId, int priorityOrder, + LOCALSubmission localSubmission) throws ServiceException { + try { + return registryHandler.addLocalSubmissionDetails(computeResourceId, priorityOrder, localSubmission); + } catch (Exception e) { + throw new ServiceException("Error while adding local job submission: " + e.getMessage(), e); + } + } + + public boolean updateLocalSubmissionDetails(String jobSubmissionInterfaceId, LOCALSubmission localSubmission) + throws ServiceException { + try { + return registryHandler.updateLocalSubmissionDetails(jobSubmissionInterfaceId, localSubmission); + } catch (Exception e) { + throw new ServiceException("Error while updating local job submission: " + e.getMessage(), e); + } + } + + public LOCALSubmission getLocalJobSubmission(String jobSubmissionId) throws ServiceException { + try { + return registryHandler.getLocalJobSubmission(jobSubmissionId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving local job submission: " + e.getMessage(), e); + } + } + + public String addSSHJobSubmissionDetails(String computeResourceId, int priorityOrder, + SSHJobSubmission sshJobSubmission) throws ServiceException { + try { + return registryHandler.addSSHJobSubmissionDetails(computeResourceId, priorityOrder, sshJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while adding SSH job submission: " + e.getMessage(), e); + } + } + + public String addSSHForkJobSubmissionDetails(String computeResourceId, int priorityOrder, + SSHJobSubmission sshJobSubmission) throws ServiceException { + try { + return registryHandler.addSSHForkJobSubmissionDetails(computeResourceId, priorityOrder, sshJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while adding SSH fork job submission: " + e.getMessage(), e); + } + } + + public SSHJobSubmission getSSHJobSubmission(String jobSubmissionId) throws ServiceException { + try { + return registryHandler.getSSHJobSubmission(jobSubmissionId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving SSH job submission: " + e.getMessage(), e); + } + } + + public String addCloudJobSubmissionDetails(String computeResourceId, int priorityOrder, + CloudJobSubmission cloudJobSubmission) throws ServiceException { + try { + return registryHandler.addCloudJobSubmissionDetails(computeResourceId, priorityOrder, cloudJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while adding cloud job submission: " + e.getMessage(), e); + } + } + + public CloudJobSubmission getCloudJobSubmission(String jobSubmissionId) throws ServiceException { + try { + return registryHandler.getCloudJobSubmission(jobSubmissionId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving cloud job submission: " + e.getMessage(), e); + } + } + + public String addUNICOREJobSubmissionDetails(String computeResourceId, int priorityOrder, + UnicoreJobSubmission unicoreJobSubmission) throws ServiceException { + try { + return registryHandler.addUNICOREJobSubmissionDetails(computeResourceId, priorityOrder, + unicoreJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while adding UNICORE job submission: " + e.getMessage(), e); + } + } + + public UnicoreJobSubmission getUnicoreJobSubmission(String jobSubmissionId) throws ServiceException { + try { + return registryHandler.getUnicoreJobSubmission(jobSubmissionId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving UNICORE job submission: " + e.getMessage(), e); + } + } + + public boolean updateSSHJobSubmissionDetails(String jobSubmissionInterfaceId, SSHJobSubmission sshJobSubmission) + throws ServiceException { + try { + return registryHandler.updateSSHJobSubmissionDetails(jobSubmissionInterfaceId, sshJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while updating SSH job submission: " + e.getMessage(), e); + } + } + + public boolean updateCloudJobSubmissionDetails(String jobSubmissionInterfaceId, + CloudJobSubmission cloudJobSubmission) throws ServiceException { + try { + return registryHandler.updateCloudJobSubmissionDetails(jobSubmissionInterfaceId, cloudJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while updating cloud job submission: " + e.getMessage(), e); + } + } + + public boolean updateUnicoreJobSubmissionDetails(String jobSubmissionInterfaceId, + UnicoreJobSubmission unicoreJobSubmission) throws ServiceException { + try { + return registryHandler.updateUnicoreJobSubmissionDetails(jobSubmissionInterfaceId, unicoreJobSubmission); + } catch (Exception e) { + throw new ServiceException("Error while updating UNICORE job submission: " + e.getMessage(), e); + } + } + + public boolean deleteJobSubmissionInterface(String computeResourceId, String jobSubmissionInterfaceId) + throws ServiceException { + try { + return registryHandler.deleteJobSubmissionInterface(computeResourceId, jobSubmissionInterfaceId); + } catch (Exception e) { + throw new ServiceException("Error while deleting job submission interface: " + e.getMessage(), e); + } + } + + // ------------------------------------------------------------------------- + // Data Movement + // ------------------------------------------------------------------------- + + public String addLocalDataMovementDetails(String resourceId, DMType dmType, int priorityOrder, + LOCALDataMovement localDataMovement) throws ServiceException { + try { + return registryHandler.addLocalDataMovementDetails(resourceId, dmType, priorityOrder, localDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while adding local data movement: " + e.getMessage(), e); + } + } + + public boolean updateLocalDataMovementDetails(String dataMovementInterfaceId, LOCALDataMovement localDataMovement) + throws ServiceException { + try { + return registryHandler.updateLocalDataMovementDetails(dataMovementInterfaceId, localDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while updating local data movement: " + e.getMessage(), e); + } + } + + public LOCALDataMovement getLocalDataMovement(String dataMovementId) throws ServiceException { + try { + return registryHandler.getLocalDataMovement(dataMovementId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving local data movement: " + e.getMessage(), e); + } + } + + public String addSCPDataMovementDetails(String resourceId, DMType dmType, int priorityOrder, + SCPDataMovement scpDataMovement) throws ServiceException { + try { + return registryHandler.addSCPDataMovementDetails(resourceId, dmType, priorityOrder, scpDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while adding SCP data movement: " + e.getMessage(), e); + } + } + + public boolean updateSCPDataMovementDetails(String dataMovementInterfaceId, SCPDataMovement scpDataMovement) + throws ServiceException { + try { + return registryHandler.updateSCPDataMovementDetails(dataMovementInterfaceId, scpDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while updating SCP data movement: " + e.getMessage(), e); + } + } + + public SCPDataMovement getSCPDataMovement(String dataMovementId) throws ServiceException { + try { + return registryHandler.getSCPDataMovement(dataMovementId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving SCP data movement: " + e.getMessage(), e); + } + } + + public String addUnicoreDataMovementDetails(String resourceId, DMType dmType, int priorityOrder, + UnicoreDataMovement unicoreDataMovement) throws ServiceException { + try { + return registryHandler.addUnicoreDataMovementDetails(resourceId, dmType, priorityOrder, + unicoreDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while adding UNICORE data movement: " + e.getMessage(), e); + } + } + + public boolean updateUnicoreDataMovementDetails(String dataMovementInterfaceId, + UnicoreDataMovement unicoreDataMovement) throws ServiceException { + try { + return registryHandler.updateUnicoreDataMovementDetails(dataMovementInterfaceId, unicoreDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while updating UNICORE data movement: " + e.getMessage(), e); + } + } + + public UnicoreDataMovement getUnicoreDataMovement(String dataMovementId) throws ServiceException { + try { + return registryHandler.getUnicoreDataMovement(dataMovementId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving UNICORE data movement: " + e.getMessage(), e); + } + } + + public String addGridFTPDataMovementDetails(String computeResourceId, DMType dmType, int priorityOrder, + GridFTPDataMovement gridFTPDataMovement) throws ServiceException { + try { + return registryHandler.addGridFTPDataMovementDetails(computeResourceId, dmType, priorityOrder, + gridFTPDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while adding GridFTP data movement: " + e.getMessage(), e); + } + } + + public boolean updateGridFTPDataMovementDetails(String dataMovementInterfaceId, + GridFTPDataMovement gridFTPDataMovement) throws ServiceException { + try { + return registryHandler.updateGridFTPDataMovementDetails(dataMovementInterfaceId, gridFTPDataMovement); + } catch (Exception e) { + throw new ServiceException("Error while updating GridFTP data movement: " + e.getMessage(), e); + } + } + + public GridFTPDataMovement getGridFTPDataMovement(String dataMovementId) throws ServiceException { + try { + return registryHandler.getGridFTPDataMovement(dataMovementId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving GridFTP data movement: " + e.getMessage(), e); + } + } + + public boolean deleteDataMovementInterface(String resourceId, String dataMovementInterfaceId, DMType dmType) + throws ServiceException { + try { + return registryHandler.deleteDataMovementInterface(resourceId, dataMovementInterfaceId, dmType); + } catch (Exception e) { + throw new ServiceException("Error while deleting data movement interface: " + e.getMessage(), e); + } + } + + // ------------------------------------------------------------------------- + // Resource Job Managers + // ------------------------------------------------------------------------- + + public String registerResourceJobManager(ResourceJobManager resourceJobManager) throws ServiceException { + try { + return registryHandler.registerResourceJobManager(resourceJobManager); + } catch (Exception e) { + throw new ServiceException("Error while adding resource job manager: " + e.getMessage(), e); + } + } + + public boolean updateResourceJobManager(String resourceJobManagerId, + ResourceJobManager updatedResourceJobManager) throws ServiceException { + try { + return registryHandler.updateResourceJobManager(resourceJobManagerId, updatedResourceJobManager); + } catch (Exception e) { + throw new ServiceException("Error while updating resource job manager: " + e.getMessage(), e); + } + } + + public ResourceJobManager getResourceJobManager(String resourceJobManagerId) throws ServiceException { + try { + return registryHandler.getResourceJobManager(resourceJobManagerId); + } catch (Exception e) { + throw new ServiceException("Error while retrieving resource job manager: " + e.getMessage(), e); + } + } + + public boolean deleteResourceJobManager(String resourceJobManagerId) throws ServiceException { + try { + return registryHandler.deleteResourceJobManager(resourceJobManagerId); + } catch (Exception e) { + throw new ServiceException("Error while deleting resource job manager: " + e.getMessage(), e); + } + } + + // ------------------------------------------------------------------------- + // Batch Queues + // ------------------------------------------------------------------------- + + public boolean deleteBatchQueue(String computeResourceId, String queueName) throws ServiceException { + try { + return registryHandler.deleteBatchQueue(computeResourceId, queueName); + } catch (Exception e) { + throw new ServiceException("Error while deleting batch queue: " + e.getMessage(), e); + } + } +} diff --git a/airavata-api/src/test/java/org/apache/airavata/service/resource/ResourceServiceTest.java b/airavata-api/src/test/java/org/apache/airavata/service/resource/ResourceServiceTest.java new file mode 100644 index 0000000000..5c97ca7700 --- /dev/null +++ b/airavata-api/src/test/java/org/apache/airavata/service/resource/ResourceServiceTest.java @@ -0,0 +1,211 @@ +package org.apache.airavata.service.resource; + +import org.apache.airavata.model.appcatalog.computeresource.*; +import org.apache.airavata.model.appcatalog.storageresource.StorageResourceDescription; +import org.apache.airavata.model.data.movement.DMType; +import org.apache.airavata.model.data.movement.GridFTPDataMovement; +import org.apache.airavata.model.data.movement.LOCALDataMovement; +import org.apache.airavata.model.data.movement.SCPDataMovement; +import org.apache.airavata.model.data.movement.UnicoreDataMovement; +import org.apache.airavata.registry.api.service.handler.RegistryServerHandler; +import org.apache.airavata.service.exception.ServiceException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ResourceServiceTest { + + @Mock RegistryServerHandler registryHandler; + + ResourceService resourceService; + + @BeforeEach + void setUp() { + resourceService = new ResourceService(registryHandler); + } + + // --- Compute Resource --- + + @Test + void registerComputeResource_returnsId() throws Exception { + ComputeResourceDescription desc = new ComputeResourceDescription(); + desc.setHostName("cluster.example.com"); + when(registryHandler.registerComputeResource(desc)).thenReturn("cr-001"); + + String result = resourceService.registerComputeResource(desc); + + assertEquals("cr-001", result); + verify(registryHandler).registerComputeResource(desc); + } + + @Test + void registerComputeResource_wrapsRegistryException() throws Exception { + ComputeResourceDescription desc = new ComputeResourceDescription(); + when(registryHandler.registerComputeResource(desc)).thenThrow(new RuntimeException("DB error")); + + assertThrows(ServiceException.class, () -> resourceService.registerComputeResource(desc)); + } + + @Test + void getComputeResource_returnsDescription() throws Exception { + ComputeResourceDescription desc = new ComputeResourceDescription(); + desc.setComputeResourceId("cr-001"); + when(registryHandler.getComputeResource("cr-001")).thenReturn(desc); + + ComputeResourceDescription result = resourceService.getComputeResource("cr-001"); + + assertNotNull(result); + assertEquals("cr-001", result.getComputeResourceId()); + } + + @Test + void deleteComputeResource_returnsTrue() throws Exception { + when(registryHandler.deleteComputeResource("cr-001")).thenReturn(true); + + boolean result = resourceService.deleteComputeResource("cr-001"); + + assertTrue(result); + } + + // --- Storage Resource --- + + @Test + void getStorageResource_returnsDescription() throws Exception { + StorageResourceDescription desc = new StorageResourceDescription(); + desc.setStorageResourceId("sr-001"); + desc.setHostName("storage.example.com"); + when(registryHandler.getStorageResource("sr-001")).thenReturn(desc); + + StorageResourceDescription result = resourceService.getStorageResource("sr-001"); + + assertNotNull(result); + assertEquals("sr-001", result.getStorageResourceId()); + } + + @Test + void getAllStorageResourceNames_returnsMap() throws Exception { + Map<String, String> names = Map.of("sr-001", "storage.example.com"); + when(registryHandler.getAllStorageResourceNames()).thenReturn(names); + + Map<String, String> result = resourceService.getAllStorageResourceNames(); + + assertEquals(1, result.size()); + assertEquals("storage.example.com", result.get("sr-001")); + } + + @Test + void deleteStorageResource_wrapsException() throws Exception { + when(registryHandler.deleteStorageResource("sr-bad")).thenThrow(new RuntimeException("not found")); + + assertThrows(ServiceException.class, () -> resourceService.deleteStorageResource("sr-bad")); + } + + // --- Job Submission --- + + @Test + void addSSHJobSubmissionDetails_returnsId() throws Exception { + SSHJobSubmission submission = new SSHJobSubmission(); + when(registryHandler.addSSHJobSubmissionDetails("cr-001", 1, submission)).thenReturn("js-001"); + + String result = resourceService.addSSHJobSubmissionDetails("cr-001", 1, submission); + + assertEquals("js-001", result); + } + + @Test + void deleteJobSubmissionInterface_returnsTrue() throws Exception { + when(registryHandler.deleteJobSubmissionInterface("cr-001", "js-001")).thenReturn(true); + + boolean result = resourceService.deleteJobSubmissionInterface("cr-001", "js-001"); + + assertTrue(result); + verify(registryHandler).deleteJobSubmissionInterface("cr-001", "js-001"); + } + + @Test + void getLocalJobSubmission_returnsSubmission() throws Exception { + LOCALSubmission submission = new LOCALSubmission(); + submission.setJobSubmissionInterfaceId("js-local-001"); + when(registryHandler.getLocalJobSubmission("js-local-001")).thenReturn(submission); + + LOCALSubmission result = resourceService.getLocalJobSubmission("js-local-001"); + + assertNotNull(result); + assertEquals("js-local-001", result.getJobSubmissionInterfaceId()); + } + + // --- Data Movement --- + + @Test + void addSCPDataMovementDetails_returnsId() throws Exception { + SCPDataMovement movement = new SCPDataMovement(); + when(registryHandler.addSCPDataMovementDetails("cr-001", DMType.COMPUTE_RESOURCE, 0, movement)) + .thenReturn("dm-001"); + + String result = resourceService.addSCPDataMovementDetails("cr-001", DMType.COMPUTE_RESOURCE, 0, movement); + + assertEquals("dm-001", result); + } + + @Test + void deleteDataMovementInterface_returnsTrue() throws Exception { + when(registryHandler.deleteDataMovementInterface("cr-001", "dm-001", DMType.COMPUTE_RESOURCE)) + .thenReturn(true); + + boolean result = resourceService.deleteDataMovementInterface("cr-001", "dm-001", DMType.COMPUTE_RESOURCE); + + assertTrue(result); + } + + @Test + void addSCPDataMovementDetails_wrapsException() throws Exception { + SCPDataMovement movement = new SCPDataMovement(); + when(registryHandler.addSCPDataMovementDetails(any(), any(), anyInt(), any())) + .thenThrow(new RuntimeException("registry failure")); + + assertThrows(ServiceException.class, + () -> resourceService.addSCPDataMovementDetails("cr-001", DMType.COMPUTE_RESOURCE, 0, movement)); + } + + // --- Resource Job Manager --- + + @Test + void registerResourceJobManager_returnsId() throws Exception { + ResourceJobManager manager = new ResourceJobManager(); + manager.setResourceJobManagerType(ResourceJobManagerType.SLURM); + when(registryHandler.registerResourceJobManager(manager)).thenReturn("rjm-001"); + + String result = resourceService.registerResourceJobManager(manager); + + assertEquals("rjm-001", result); + } + + @Test + void deleteResourceJobManager_returnsTrue() throws Exception { + when(registryHandler.deleteResourceJobManager("rjm-001")).thenReturn(true); + + boolean result = resourceService.deleteResourceJobManager("rjm-001"); + + assertTrue(result); + } + + // --- Batch Queue --- + + @Test + void deleteBatchQueue_returnsTrue() throws Exception { + when(registryHandler.deleteBatchQueue("cr-001", "normal")).thenReturn(true); + + boolean result = resourceService.deleteBatchQueue("cr-001", "normal"); + + assertTrue(result); + verify(registryHandler).deleteBatchQueue("cr-001", "normal"); + } +}
