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

machristie pushed a commit to branch airavata-v2-refactoring
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit 2e7e51a1b85254d4d0b7e02f400487b4b711d404
Author: Marcus Christie <[email protected]>
AuthorDate: Wed Jun 14 18:24:31 2023 -0400

    Adding transactional service layer for ExecutionHandler
---
 .../apis/exception/EntityNotFoundException.java    | 23 +++++++++
 .../airavata/apis/handlers/ExecutionHandler.java   | 43 +++++-----------
 .../airavata/apis/service/ExecutionService.java    | 13 +++++
 .../apis/service/impl/ExecutionServiceImpl.java    | 57 ++++++++++++++++++++++
 4 files changed, 106 insertions(+), 30 deletions(-)

diff --git 
a/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/exception/EntityNotFoundException.java
 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/exception/EntityNotFoundException.java
new file mode 100644
index 0000000000..c4bc4bcc50
--- /dev/null
+++ 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/exception/EntityNotFoundException.java
@@ -0,0 +1,23 @@
+package org.apache.airavata.apis.exception;
+
+public class EntityNotFoundException extends RuntimeException {
+    public EntityNotFoundException() {
+    }
+
+    public EntityNotFoundException(String message) {
+        super(message);
+    }
+
+    public EntityNotFoundException(Throwable cause) {
+        super(cause);
+    }
+
+    public EntityNotFoundException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public EntityNotFoundException(String message, Throwable cause, boolean 
enableSuppression,
+            boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git 
a/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/handlers/ExecutionHandler.java
 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/handlers/ExecutionHandler.java
index 634dc41f2b..e6a48aff1b 100644
--- 
a/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/handlers/ExecutionHandler.java
+++ 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/handlers/ExecutionHandler.java
@@ -1,18 +1,15 @@
 package org.apache.airavata.apis.handlers;
 
+import io.grpc.Status;
 import io.grpc.stub.StreamObserver;
 import org.apache.airavata.api.execution.*;
 import org.apache.airavata.api.execution.stubs.Experiment;
-import org.apache.airavata.apis.db.entity.ExperimentEntity;
-import org.apache.airavata.apis.db.repository.ExperimentRepository;
-import org.apache.airavata.apis.db.repository.RunConfigurationRepository;
-import org.apache.airavata.apis.mapper.ExperimentMapper;
+import org.apache.airavata.apis.exception.EntityNotFoundException;
 import org.apache.airavata.apis.scheduling.MetaScheduler;
+import org.apache.airavata.apis.service.ExecutionService;
 import org.lognet.springboot.grpc.GRpcService;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import java.util.Optional;
-
 @GRpcService
 public class ExecutionHandler extends 
ExecutionServiceGrpc.ExecutionServiceImplBase {
 
@@ -20,25 +17,17 @@ public class ExecutionHandler extends 
ExecutionServiceGrpc.ExecutionServiceImplB
     private MetaScheduler metaScheduler;
 
     @Autowired
-    ExperimentRepository experimentRepository;
-
-    @Autowired
-    RunConfigurationRepository runConfigurationRepository;
+    private ExecutionService executionService;
 
-    @Autowired
-    ExperimentMapper experimentMapper;
-
-    // TODO: factor out database stuff into a transactional service layer
     @Override
     public void registerExperiment(ExperimentRegisterRequest request, 
StreamObserver<ExperimentRegisterResponse> responseObserver) {
 
         Experiment experiment = request.getExperiment();
 
-        ExperimentEntity experimentEntity = 
experimentMapper.mapModelToEntity(experiment);
-        ExperimentEntity savedExperimentEntity = 
experimentRepository.save(experimentEntity);
+        Experiment savedExperiment = 
executionService.createExperiment(experiment);
 
         responseObserver.onNext(ExperimentRegisterResponse.newBuilder()
-                
.setExperimentId(savedExperimentEntity.getExperimentId()).build());
+                .setExperimentId(savedExperiment.getExperimentId()).build());
         responseObserver.onCompleted();
     }
 
@@ -47,19 +36,13 @@ public class ExecutionHandler extends 
ExecutionServiceGrpc.ExecutionServiceImplB
             StreamObserver<ExperimentUpdateResponse> responseObserver) {
 
         Experiment experiment = request.getExperiment();
-        Optional<ExperimentEntity> maybeExperimentEntity = 
experimentRepository.findById(experiment.getExperimentId());
-        // TODO: handle experiment not found
-        maybeExperimentEntity.ifPresent(entity -> {
-            // First delete any existing run configs
-            if (entity.getRunConfigs() != null && 
!entity.getRunConfigs().isEmpty()) {
-                runConfigurationRepository.deleteAll(entity.getRunConfigs());
-                entity.setRunConfigs(null);
-            }
-            experimentMapper.mapModelToEntity(experiment, entity);
-            experimentRepository.save(entity);
-        });
-        responseObserver.onNext(ExperimentUpdateResponse.getDefaultInstance());
-        responseObserver.onCompleted();
+        try {
+            executionService.updateExperiment(experiment);
+            
responseObserver.onNext(ExperimentUpdateResponse.getDefaultInstance());
+            responseObserver.onCompleted();
+        } catch (EntityNotFoundException e) {
+            
responseObserver.onError(Status.NOT_FOUND.withDescription(e.getMessage()).asException());
+        }
     }
 
     @Override
diff --git 
a/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/ExecutionService.java
 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/ExecutionService.java
new file mode 100644
index 0000000000..fe37625491
--- /dev/null
+++ 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/ExecutionService.java
@@ -0,0 +1,13 @@
+package org.apache.airavata.apis.service;
+
+import org.apache.airavata.api.execution.stubs.Experiment;
+
+/**
+ * Transactional service layer for CRUD operations on database.
+ */
+public interface ExecutionService {
+
+    Experiment createExperiment(Experiment experiment);
+
+    Experiment updateExperiment(Experiment experiment);
+}
diff --git 
a/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/impl/ExecutionServiceImpl.java
 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/impl/ExecutionServiceImpl.java
new file mode 100644
index 0000000000..ed94225800
--- /dev/null
+++ 
b/modules/airavata-apis/airavata-apis-server/src/main/java/org/apache/airavata/apis/service/impl/ExecutionServiceImpl.java
@@ -0,0 +1,57 @@
+package org.apache.airavata.apis.service.impl;
+
+import org.apache.airavata.api.execution.stubs.Experiment;
+import org.apache.airavata.apis.db.entity.ExperimentEntity;
+import org.apache.airavata.apis.db.repository.ExperimentRepository;
+import org.apache.airavata.apis.db.repository.RunConfigurationRepository;
+import org.apache.airavata.apis.exception.EntityNotFoundException;
+import org.apache.airavata.apis.mapper.ExperimentMapper;
+import org.apache.airavata.apis.service.ExecutionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+
+import java.util.Optional;
+
+// See 
https://github.com/LogNet/grpc-spring-boot-starter#9-grpc-response-observer--and-spring-transactional-caveats
+@Service
+@Transactional
+public class ExecutionServiceImpl implements ExecutionService {
+
+    @Autowired
+    ExperimentRepository experimentRepository;
+
+    @Autowired
+    RunConfigurationRepository runConfigurationRepository;
+
+    @Autowired
+    ExperimentMapper experimentMapper;
+
+    @Override
+    public Experiment createExperiment(Experiment experiment) {
+
+        ExperimentEntity experimentEntity = 
experimentMapper.mapModelToEntity(experiment);
+        ExperimentEntity savedExperimentEntity = 
experimentRepository.save(experimentEntity);
+        return experimentMapper.mapEntityToModel(savedExperimentEntity);
+    }
+
+    @Override
+    public Experiment updateExperiment(Experiment experiment) {
+        Optional<ExperimentEntity> maybeExperimentEntity = 
experimentRepository.findById(experiment.getExperimentId());
+        if (maybeExperimentEntity.isEmpty()) {
+            throw new EntityNotFoundException("No experiment exists with id " 
+ experiment.getExperimentId());
+        }
+        ExperimentEntity experimentEntity = maybeExperimentEntity.get();
+        // First delete any existing run configs
+        if (experimentEntity.getRunConfigs() != null && 
!experimentEntity.getRunConfigs().isEmpty()) {
+            
runConfigurationRepository.deleteAll(experimentEntity.getRunConfigs());
+            experimentEntity.setRunConfigs(null);
+        }
+        experimentMapper.mapModelToEntity(experiment, experimentEntity);
+        experimentRepository.save(experimentEntity);
+        return experimentMapper.mapEntityToModel(experimentEntity);
+
+    }
+
+}

Reply via email to