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 2c02d90ba884dfa516b5ed4f06227e92e7058951
Author: yasithdev <[email protected]>
AuthorDate: Thu Mar 26 10:57:40 2026 -0500

    feat: add remaining experiment methods to ExperimentService
    
    Adds getExperimentStatistics, getExperimentsInProject, getUserExperiments,
    getDetailedExperimentTree, updateExperiment, updateExperimentConfiguration,
    updateResourceScheduleing, validateExperiment, getJobStatuses, 
getJobDetails.
    Rewires corresponding AiravataServerHandler methods to ThriftAdapter 
one-liners.
---
 .../service/experiment/ExperimentService.java      | 132 +++++++++++++++++++++
 .../service/experiment/ExperimentServiceTest.java  |  46 +++++++
 2 files changed, 178 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
index e03b725a00..b1d61e3125 100644
--- 
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
@@ -2,11 +2,17 @@ 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.ExperimentStatistics;
 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.job.JobModel;
+import 
org.apache.airavata.model.scheduling.ComputationalResourceSchedulingModel;
 import org.apache.airavata.model.status.ExperimentState;
 import org.apache.airavata.model.status.ExperimentStatus;
+import org.apache.airavata.model.status.JobStatus;
+import org.apache.airavata.model.workspace.Project;
+import org.apache.airavata.model.experiment.UserConfigurationDataModel;
 import org.apache.airavata.registry.api.service.handler.RegistryServerHandler;
 import org.apache.airavata.service.context.RequestContext;
 import org.apache.airavata.service.exception.ServiceAuthorizationException;
@@ -336,6 +342,132 @@ public class ExperimentService {
         }
     }
 
+    public ExperimentStatistics getExperimentStatistics(
+            RequestContext ctx, String gatewayId, long fromTime, long toTime,
+            String userName, String applicationName, String resourceHostName,
+            int limit, int offset) throws ServiceException {
+        try {
+            return registryHandler.getExperimentStatistics(
+                    gatewayId, fromTime, toTime, userName, applicationName,
+                    resourceHostName, null, limit, offset);
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving experiment 
statistics: " + e.getMessage(), e);
+        }
+    }
+
+    public List<ExperimentModel> getExperimentsInProject(
+            RequestContext ctx, String projectId, int limit, int offset) 
throws ServiceException {
+        try {
+            Project project = registryHandler.getProject(projectId);
+            if (isSharingEnabled()
+                    && (!ctx.getUserId().equals(project.getOwner())
+                        || 
!ctx.getGatewayId().equals(project.getGatewayId()))) {
+                String qualifiedUserId = ctx.getUserId() + "@" + 
ctx.getGatewayId();
+                if (!sharingHandler.userHasAccess(
+                        ctx.getGatewayId(), qualifiedUserId, projectId, 
ctx.getGatewayId() + ":READ")) {
+                    throw new ServiceAuthorizationException(
+                            "User does not have permission to access this 
resource");
+                }
+            }
+            return registryHandler.getExperimentsInProject(ctx.getGatewayId(), 
projectId, limit, offset);
+        } catch (ServiceException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving experiments in 
project: " + e.getMessage(), e);
+        }
+    }
+
+    public List<ExperimentModel> getUserExperiments(
+            RequestContext ctx, String gatewayId, String userName, int limit, 
int offset) throws ServiceException {
+        try {
+            return registryHandler.getUserExperiments(gatewayId, userName, 
limit, offset);
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving user 
experiments: " + e.getMessage(), e);
+        }
+    }
+
+    public ExperimentModel getDetailedExperimentTree(RequestContext ctx, 
String experimentId)
+            throws ServiceException {
+        try {
+            return registryHandler.getDetailedExperimentTree(experimentId);
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving experiment 
tree: " + e.getMessage(), e);
+        }
+    }
+
+    public void updateExperiment(RequestContext ctx, String experimentId, 
ExperimentModel experiment)
+            throws ServiceException {
+        try {
+            ExperimentModel existing = 
registryHandler.getExperiment(experimentId);
+            if (isSharingEnabled()
+                    && (!ctx.getUserId().equals(existing.getUserName())
+                        || 
!ctx.getGatewayId().equals(existing.getGatewayId()))) {
+                String qualifiedUserId = ctx.getUserId() + "@" + 
ctx.getGatewayId();
+                if (!sharingHandler.userHasAccess(
+                        ctx.getGatewayId(), qualifiedUserId, experimentId,
+                        ctx.getGatewayId() + ":WRITE")) {
+                    throw new ServiceAuthorizationException(
+                            "User does not have permission to update this 
resource");
+                }
+            }
+            if (isSharingEnabled()) {
+                try {
+                    Entity entity = 
sharingHandler.getEntity(ctx.getGatewayId(), experimentId);
+                    entity.setName(experiment.getExperimentName());
+                    entity.setDescription(experiment.getDescription());
+                    entity.setParentEntityId(experiment.getProjectId());
+                    sharingHandler.updateEntity(entity);
+                } catch (Exception e) {
+                    throw new ServiceException("Failed to update entity in 
sharing registry", e);
+                }
+            }
+            registryHandler.updateExperiment(experimentId, experiment);
+        } catch (ServiceException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ServiceException("Error while updating experiment: " + 
e.getMessage(), e);
+        }
+    }
+
+    public void updateExperimentConfiguration(RequestContext ctx, String 
experimentId,
+            UserConfigurationDataModel userConfiguration) throws 
ServiceException {
+        try {
+            registryHandler.updateExperimentConfiguration(experimentId, 
userConfiguration);
+        } catch (Exception e) {
+            throw new ServiceException("Error while updating experiment 
configuration: " + e.getMessage(), e);
+        }
+    }
+
+    public void updateResourceScheduleing(RequestContext ctx, String 
experimentId,
+            ComputationalResourceSchedulingModel resourceScheduling) throws 
ServiceException {
+        try {
+            registryHandler.updateResourceScheduleing(experimentId, 
resourceScheduling);
+        } catch (Exception e) {
+            throw new ServiceException("Error while updating resource 
scheduling: " + e.getMessage(), e);
+        }
+    }
+
+    public boolean validateExperiment(RequestContext ctx, String experimentId) 
throws ServiceException {
+        // TODO: call validation module and validate experiment
+        return true;
+    }
+
+    public Map<String, JobStatus> getJobStatuses(RequestContext ctx, String 
experimentId) throws ServiceException {
+        try {
+            return registryHandler.getJobStatuses(experimentId);
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving job statuses: " 
+ e.getMessage(), e);
+        }
+    }
+
+    public List<JobModel> getJobDetails(RequestContext ctx, String 
experimentId) throws ServiceException {
+        try {
+            return registryHandler.getJobDetails(experimentId);
+        } catch (Exception e) {
+            throw new ServiceException("Error while retrieving job details: " 
+ e.getMessage(), e);
+        }
+    }
+
     private boolean isSharingEnabled() {
         try {
             return ServerSettings.isEnableSharing();
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
index cd549165b9..a62c77e095 100644
--- 
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
@@ -1,8 +1,10 @@
 package org.apache.airavata.service.experiment;
 
 import org.apache.airavata.model.experiment.ExperimentModel;
+import org.apache.airavata.model.experiment.ExperimentStatistics;
 import org.apache.airavata.model.status.ExperimentState;
 import org.apache.airavata.model.status.ExperimentStatus;
+import org.apache.airavata.model.status.JobStatus;
 import org.apache.airavata.model.application.io.OutputDataObjectType;
 import org.apache.airavata.registry.api.service.handler.RegistryServerHandler;
 import org.apache.airavata.service.context.RequestContext;
@@ -21,6 +23,7 @@ import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.doNothing;
 
 @ExtendWith(MockitoExtension.class)
 class ExperimentServiceTest {
@@ -131,4 +134,47 @@ class ExperimentServiceTest {
         List<OutputDataObjectType> result = 
experimentService.getExperimentOutputs(ctx, "exp-123");
         assertEquals(1, result.size());
     }
+
+    @Test
+    void getExperimentStatistics_delegatesToRegistry() throws Exception {
+        ExperimentStatistics stats = new ExperimentStatistics();
+        stats.setAllExperimentCount(5);
+        when(registryHandler.getExperimentStatistics(
+                "testGateway", 1000L, 2000L, null, null, null, null, 10, 0))
+                .thenReturn(stats);
+        ExperimentStatistics result = 
experimentService.getExperimentStatistics(
+                ctx, "testGateway", 1000L, 2000L, null, null, null, 10, 0);
+        assertEquals(5, result.getAllExperimentCount());
+    }
+
+    @Test
+    void updateExperiment_ownerCanUpdate() throws Exception {
+        ExperimentModel existing = new ExperimentModel();
+        existing.setUserName("testUser");
+        existing.setGatewayId("testGateway");
+        ExperimentModel updated = new ExperimentModel();
+        updated.setExperimentName("new-name");
+        updated.setProjectId("proj-1");
+
+        when(registryHandler.getExperiment("exp-123")).thenReturn(existing);
+        doNothing().when(registryHandler).updateExperiment("exp-123", updated);
+
+        // Should not throw — owner has implicit WRITE
+        assertDoesNotThrow(() -> experimentService.updateExperiment(ctx, 
"exp-123", updated));
+        verify(registryHandler).updateExperiment("exp-123", updated);
+    }
+
+    @Test
+    void getJobStatuses_delegatesToRegistry() throws Exception {
+        Map<String, JobStatus> statuses = Map.of("job-1", new JobStatus());
+        when(registryHandler.getJobStatuses("exp-123")).thenReturn(statuses);
+        Map<String, JobStatus> result = experimentService.getJobStatuses(ctx, 
"exp-123");
+        assertEquals(1, result.size());
+    }
+
+    @Test
+    void validateExperiment_returnsTrue() throws Exception {
+        boolean result = experimentService.validateExperiment(ctx, "exp-123");
+        assertTrue(result);
+    }
 }

Reply via email to