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 9ac360eda713035b4a9757abe59141dcc2238ec3 Author: yasithdev <[email protected]> AuthorDate: Thu Mar 26 05:31:43 2026 -0500 feat: add ExperimentService with createExperiment and getExperiment Extracts experiment business logic from AiravataServerHandler into a clean service class with explicit dependency injection. Uses isSharingEnabled() helper to safely default to false when the setting is absent. --- .../service/experiment/ExperimentService.java | 119 +++++++++++++++++++++ .../service/experiment/ExperimentServiceTest.java | 65 +++++++++++ 2 files changed, 184 insertions(+) diff --git a/airavata-api/src/main/java/org/apache/airavata/service/experiment/ExperimentService.java b/airavata-api/src/main/java/org/apache/airavata/service/experiment/ExperimentService.java new file mode 100644 index 0000000000..906e61902a --- /dev/null +++ b/airavata-api/src/main/java/org/apache/airavata/service/experiment/ExperimentService.java @@ -0,0 +1,119 @@ +package org.apache.airavata.service.experiment; + +import org.apache.airavata.common.utils.ServerSettings; +import org.apache.airavata.model.experiment.ExperimentModel; +import org.apache.airavata.model.experiment.ExperimentSummaryModel; +import org.apache.airavata.model.experiment.ExperimentSearchFields; +import org.apache.airavata.model.application.io.OutputDataObjectType; +import org.apache.airavata.model.status.ExperimentState; +import org.apache.airavata.model.status.ExperimentStatus; +import org.apache.airavata.registry.api.service.handler.RegistryServerHandler; +import org.apache.airavata.service.context.RequestContext; +import org.apache.airavata.service.exception.ServiceAuthorizationException; +import org.apache.airavata.service.exception.ServiceException; +import org.apache.airavata.service.exception.ServiceNotFoundException; +import org.apache.airavata.service.messaging.EventPublisher; +import org.apache.airavata.sharing.registry.models.Entity; +import org.apache.airavata.sharing.registry.models.SearchCriteria; +import org.apache.airavata.sharing.registry.models.EntitySearchField; +import org.apache.airavata.sharing.registry.models.SearchCondition; +import org.apache.airavata.sharing.registry.server.SharingRegistryServerHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ExperimentService { + + private static final Logger logger = LoggerFactory.getLogger(ExperimentService.class); + + private final RegistryServerHandler registryHandler; + private final SharingRegistryServerHandler sharingHandler; + private final EventPublisher eventPublisher; + + public ExperimentService( + RegistryServerHandler registryHandler, + SharingRegistryServerHandler sharingHandler, + EventPublisher eventPublisher) { + this.registryHandler = registryHandler; + this.sharingHandler = sharingHandler; + this.eventPublisher = eventPublisher; + } + + public String createExperiment(RequestContext ctx, ExperimentModel experiment) throws ServiceException { + try { + String experimentId = registryHandler.createExperiment(ctx.getGatewayId(), experiment); + + if (isSharingEnabled()) { + try { + Entity entity = new Entity(); + entity.setEntityId(experimentId); + String domainId = experiment.getGatewayId(); + entity.setDomainId(domainId); + entity.setEntityTypeId(domainId + ":" + "EXPERIMENT"); + entity.setOwnerId(experiment.getUserName() + "@" + domainId); + entity.setName(experiment.getExperimentName()); + entity.setDescription(experiment.getDescription()); + entity.setParentEntityId(experiment.getProjectId()); + sharingHandler.createEntity(entity); + } catch (Exception ex) { + logger.error("Rolling back experiment creation Exp ID : {}", experimentId, ex); + registryHandler.deleteExperiment(experimentId); + throw new ServiceException("Failed to create sharing registry record", ex); + } + } + + eventPublisher.publishExperimentStatus(experimentId, ctx.getGatewayId(), ExperimentState.CREATED); + logger.info("Created new experiment with name {} and id {}", + experiment.getExperimentName(), experimentId); + return experimentId; + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + throw new ServiceException("Error while creating the experiment: " + e.getMessage(), e); + } + } + + public ExperimentModel getExperiment(RequestContext ctx, String experimentId) throws ServiceException { + try { + ExperimentModel experiment = registryHandler.getExperiment(experimentId); + if (experiment == null) { + throw new ServiceNotFoundException("Experiment " + experimentId + " does not exist"); + } + + // Owner always has access + if (ctx.getUserId().equals(experiment.getUserName()) + && ctx.getGatewayId().equals(experiment.getGatewayId())) { + return experiment; + } + + // Check sharing permissions + if (isSharingEnabled()) { + String qualifiedUserId = ctx.getUserId() + "@" + ctx.getGatewayId(); + if (!sharingHandler.userHasAccess( + ctx.getGatewayId(), qualifiedUserId, experimentId, ctx.getGatewayId() + ":READ")) { + throw new ServiceAuthorizationException( + "User does not have permission to access this resource"); + } + return experiment; + } + + return null; + } catch (ServiceException e) { + throw e; + } catch (Exception e) { + throw new ServiceException("Error while getting the experiment: " + e.getMessage(), e); + } + } + + private boolean isSharingEnabled() { + try { + return ServerSettings.isEnableSharing(); + } catch (Exception e) { + return false; + } + } +} diff --git a/airavata-api/src/test/java/org/apache/airavata/service/experiment/ExperimentServiceTest.java b/airavata-api/src/test/java/org/apache/airavata/service/experiment/ExperimentServiceTest.java new file mode 100644 index 0000000000..ff78ade708 --- /dev/null +++ b/airavata-api/src/test/java/org/apache/airavata/service/experiment/ExperimentServiceTest.java @@ -0,0 +1,65 @@ +package org.apache.airavata.service.experiment; + +import org.apache.airavata.model.experiment.ExperimentModel; +import org.apache.airavata.registry.api.service.handler.RegistryServerHandler; +import org.apache.airavata.service.context.RequestContext; +import org.apache.airavata.service.messaging.EventPublisher; +import org.apache.airavata.sharing.registry.server.SharingRegistryServerHandler; +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 ExperimentServiceTest { + + @Mock RegistryServerHandler registryHandler; + @Mock SharingRegistryServerHandler sharingHandler; + @Mock EventPublisher eventPublisher; + + ExperimentService experimentService; + RequestContext ctx; + + @BeforeEach + void setUp() { + experimentService = new ExperimentService(registryHandler, sharingHandler, eventPublisher); + ctx = new RequestContext("testUser", "testGateway", "token123", + Map.of("userName", "testUser", "gatewayId", "testGateway")); + } + + @Test + void createExperiment_returnsExperimentId() throws Exception { + ExperimentModel experiment = new ExperimentModel(); + experiment.setExperimentName("test-exp"); + experiment.setGatewayId("testGateway"); + experiment.setUserName("testUser"); + experiment.setProjectId("proj-1"); + + when(registryHandler.createExperiment("testGateway", experiment)).thenReturn("exp-123"); + + String result = experimentService.createExperiment(ctx, experiment); + + assertEquals("exp-123", result); + verify(registryHandler).createExperiment("testGateway", experiment); + } + + @Test + void getExperiment_ownerGetsAccess() throws Exception { + ExperimentModel experiment = new ExperimentModel(); + experiment.setUserName("testUser"); + experiment.setGatewayId("testGateway"); + + when(registryHandler.getExperiment("exp-123")).thenReturn(experiment); + + ExperimentModel result = experimentService.getExperiment(ctx, "exp-123"); + + assertNotNull(result); + assertEquals("testUser", result.getUserName()); + } +}
