You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ya...@apache.org on 2025/12/11 16:10:05 UTC
(airavata) 15/19: reduce wrapper codes, merge duplicates and cleanup structure.
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
commit 352542b84b514f102b0a27d9b69579e9f8d83f37
Author: yasithdev <ya...@icloud.com>
AuthorDate: Tue Dec 9 19:08:48 2025 -0600
reduce wrapper codes, merge duplicates and cleanup structure.
---
.../org/apache/airavata/agents/api/AgentUtils.java | 46 ----
.../api/thrift/handler/AiravataServiceHandler.java | 6 +-
.../thrift/handler/CredentialServiceHandler.java | 3 +-
.../thrift/handler/GroupManagerServiceHandler.java | 11 +-
.../api/thrift/handler/IamAdminServiceHandler.java | 6 +-
.../api/thrift/handler/RegistryServiceHandler.java | 11 +-
.../handler/SharingRegistryServerHandler.java | 13 +-
.../handler/TenantProfileServiceHandler.java | 11 +-
.../thrift/handler/UserProfileServiceHandler.java | 3 +-
.../api/thrift/server/SharingRegistryServer.java | 9 +-
.../common/exception/ErrorCodeGenerator.java | 68 ++++++
.../common/exception/ExceptionHandlerUtil.java | 149 +++++++++++++
.../airavata/common/logging/LoggingUtil.java | 247 +++++++++++++++++++++
.../apache/airavata/common/logging/MDCUtil.java | 47 ----
.../common/repositories/AbstractRepository.java | 173 +++++++++++++++
.../common/validation/ValidationResult.java | 148 ++++++++++++
.../common/validation/ValidationService.java | 141 ++++++++++++
.../helix/impl/task/aws/AWSCompletingTask.java | 4 +
.../task/cancel/RemoteJobCancellationTask.java | 8 +-
.../impl/task/cancel/WorkflowCancellationTask.java | 4 +
.../helix/impl/task/parsing/DataParsingTask.java | 4 +
.../task/submission/DefaultJobSubmissionTask.java | 4 +
.../parser/AiravataCustomCommandOutputParser.java | 9 +
.../messaging/client/RabbitMQListener.java | 9 -
.../monitor/email/parser/PBSEmailParser.java | 3 +-
.../monitor/kafka/JobStatusResultDeserializer.java | 8 +
.../monitor/kafka/JobStatusResultSerializer.java | 8 +
.../utils/TenantManagementKeycloakImpl.java | 3 +-
.../airavata/registry/cpi/ReplicaCatalog.java | 28 ---
.../registry/services/BaseErrorService.java | 119 ++++++++++
.../registry/services/ExperimentErrorService.java | 70 ++++--
.../registry/services/ExperimentService.java | 10 +-
.../services/GwyResourceProfileService.java | 14 +-
.../registry/services/ProcessErrorService.java | 70 ++++--
.../airavata/registry/services/ProcessService.java | 12 +-
.../registry/services/TaskErrorService.java | 70 ++++--
.../services/UserResourceProfileService.java | 16 +-
.../apache/airavata/service/AiravataService.java | 131 +++++------
.../airavata/service/OrchestratorService.java | 4 +-
.../messaging/SharingServiceDBEventHandler.java | 3 +-
.../sharing/repositories/AbstractRepository.java | 70 +++++-
41 files changed, 1448 insertions(+), 325 deletions(-)
diff --git a/airavata-api/src/main/java/org/apache/airavata/agents/api/AgentUtils.java b/airavata-api/src/main/java/org/apache/airavata/agents/api/AgentUtils.java
deleted file mode 100644
index c78831033c..0000000000
--- a/airavata-api/src/main/java/org/apache/airavata/agents/api/AgentUtils.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
-*
-* 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.agents.api;
-
-import org.apache.airavata.service.CredentialStoreService;
-import org.apache.airavata.service.RegistryService;
-import org.springframework.stereotype.Component;
-
-@Component
-public class AgentUtils {
-
- private final RegistryService registryService;
- private final CredentialStoreService credentialStoreService;
-
- public AgentUtils(
- RegistryService registryService,
- CredentialStoreService credentialStoreService) {
- this.registryService = registryService;
- this.credentialStoreService = credentialStoreService;
- }
-
- public RegistryService getRegistryService() {
- return registryService;
- }
-
- public CredentialStoreService getCredentialService() {
- return credentialStoreService;
- }
-}
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/AiravataServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/AiravataServiceHandler.java
index 41aa5527e0..75255155be 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/AiravataServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/AiravataServiceHandler.java
@@ -23,8 +23,6 @@ import java.util.*;
import org.apache.airavata.accountprovisioning.ConfigParam;
import org.apache.airavata.accountprovisioning.SSHAccountProvisionerFactory;
import org.apache.airavata.accountprovisioning.SSHAccountProvisionerProvider;
-import org.apache.airavata.api.Airavata;
-import org.apache.airavata.api.airavata_apiConstants;
import org.apache.airavata.common.exception.AiravataException;
import org.apache.airavata.common.exception.ApplicationSettingsException;
import org.apache.airavata.common.utils.Constants;
@@ -77,7 +75,7 @@ import org.apache.airavata.sharing.models.SharingRegistryException;
import org.springframework.stereotype.Component;
@Component
-public class AiravataServiceHandler implements Airavata.Iface {
+public class AiravataServiceHandler implements org.apache.airavata.api.Airavata.Iface {
private final AiravataService airavataService;
@@ -91,7 +89,7 @@ public class AiravataServiceHandler implements Airavata.Iface {
*/
@Override
public String getAPIVersion() throws AiravataSystemException {
- return airavata_apiConstants.AIRAVATA_API_VERSION;
+ return org.apache.airavata.api.airavata_apiConstants.AIRAVATA_API_VERSION;
}
/**
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/CredentialServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/CredentialServiceHandler.java
index 168858cc3c..b222cd3afa 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/CredentialServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/CredentialServiceHandler.java
@@ -21,7 +21,6 @@ package org.apache.airavata.api.thrift.handler;
import java.util.List;
import java.util.Map;
-import org.apache.airavata.credential.cpi.credential_store_cpiConstants;
import org.apache.airavata.credential.exception.CredentialStoreException;
import org.apache.airavata.model.credential.store.*;
import org.apache.airavata.model.error.AiravataSystemException;
@@ -42,7 +41,7 @@ public class CredentialServiceHandler implements org.apache.airavata.credential.
@Override
public String getAPIVersion() throws AiravataSystemException {
- return credential_store_cpiConstants.CS_CPI_VERSION;
+ return org.apache.airavata.credential.cpi.credential_store_cpiConstants.CS_CPI_VERSION;
}
private CredentialStoreException wrapException(
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/GroupManagerServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/GroupManagerServiceHandler.java
index 884b35eb16..82b45aae6e 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/GroupManagerServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/GroupManagerServiceHandler.java
@@ -24,29 +24,28 @@ import org.apache.airavata.model.error.AiravataSystemException;
import org.apache.airavata.model.error.AuthorizationException;
import org.apache.airavata.model.group.GroupModel;
import org.apache.airavata.model.security.AuthzToken;
-import org.apache.airavata.profile.groupmanager.cpi.GroupManagerService;
import org.apache.airavata.profile.groupmanager.cpi.exception.GroupManagerServiceException;
-import org.apache.airavata.profile.groupmanager.cpi.group_manager_cpiConstants;
import org.apache.airavata.security.interceptor.SecurityCheck;
+import org.apache.airavata.service.GroupManagerService;
import org.apache.airavata.sharing.models.SharingRegistryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
-public class GroupManagerServiceHandler implements GroupManagerService.Iface {
+public class GroupManagerServiceHandler implements org.apache.airavata.profile.groupmanager.cpi.GroupManagerService.Iface {
private static final Logger logger = LoggerFactory.getLogger(GroupManagerServiceHandler.class);
- private final org.apache.airavata.service.GroupManagerService groupManagerService;
+ private final GroupManagerService groupManagerService;
- public GroupManagerServiceHandler(org.apache.airavata.service.GroupManagerService groupManagerService) {
+ public GroupManagerServiceHandler(GroupManagerService groupManagerService) {
this.groupManagerService = groupManagerService;
logger.info("GroupManagerServiceHandler initialized with Spring-injected GroupManagerService");
}
@Override
public String getAPIVersion() throws AiravataSystemException {
- return group_manager_cpiConstants.GROUP_MANAGER_CPI_VERSION;
+ return org.apache.airavata.profile.groupmanager.cpi.group_manager_cpiConstants.GROUP_MANAGER_CPI_VERSION;
}
@Override
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/IamAdminServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/IamAdminServiceHandler.java
index 57f8066453..5fdb186750 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/IamAdminServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/IamAdminServiceHandler.java
@@ -26,9 +26,7 @@ import org.apache.airavata.model.error.AuthorizationException;
import org.apache.airavata.model.security.AuthzToken;
import org.apache.airavata.model.user.UserProfile;
import org.apache.airavata.model.workspace.Gateway;
-import org.apache.airavata.profile.iam.admin.services.cpi.IamAdminServices;
import org.apache.airavata.profile.iam.admin.services.cpi.exception.IamAdminServicesException;
-import org.apache.airavata.profile.iam.admin.services.cpi.iam_admin_services_cpiConstants;
import org.apache.airavata.registry.api.exception.RegistryServiceException;
import org.apache.airavata.security.interceptor.SecurityCheck;
import org.apache.airavata.service.IamAdminService;
@@ -37,7 +35,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
-public class IamAdminServiceHandler implements IamAdminServices.Iface {
+public class IamAdminServiceHandler implements org.apache.airavata.profile.iam.admin.services.cpi.IamAdminServices.Iface {
private static final Logger logger = LoggerFactory.getLogger(IamAdminServiceHandler.class);
private final IamAdminService iamAdminService;
@@ -49,7 +47,7 @@ public class IamAdminServiceHandler implements IamAdminServices.Iface {
@Override
public String getAPIVersion() throws AiravataSystemException {
- return iam_admin_services_cpiConstants.IAM_ADMIN_SERVICES_CPI_VERSION;
+ return org.apache.airavata.profile.iam.admin.services.cpi.iam_admin_services_cpiConstants.IAM_ADMIN_SERVICES_CPI_VERSION;
}
@Override
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/RegistryServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/RegistryServiceHandler.java
index e5acc00b17..9b35f38d80 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/RegistryServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/RegistryServiceHandler.java
@@ -61,20 +61,19 @@ import org.apache.airavata.model.workspace.Gateway;
import org.apache.airavata.model.workspace.GatewayUsageReportingCommand;
import org.apache.airavata.model.workspace.Notification;
import org.apache.airavata.model.workspace.Project;
-import org.apache.airavata.registry.api.RegistryService;
import org.apache.airavata.registry.api.exception.RegistryServiceException;
-import org.apache.airavata.registry.api.registry_apiConstants;
+import org.apache.airavata.service.RegistryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
-public class RegistryServiceHandler implements RegistryService.Iface {
+public class RegistryServiceHandler implements org.apache.airavata.registry.api.RegistryService.Iface {
private static final Logger logger = LoggerFactory.getLogger(RegistryServiceHandler.class);
- private final org.apache.airavata.service.RegistryService registryService;
+ private final RegistryService registryService;
- public RegistryServiceHandler(org.apache.airavata.service.RegistryService registryService) {
+ public RegistryServiceHandler(RegistryService registryService) {
this.registryService = registryService;
}
@@ -91,7 +90,7 @@ public class RegistryServiceHandler implements RegistryService.Iface {
*/
@Override
public String getAPIVersion() throws AiravataSystemException {
- return registry_apiConstants.REGISTRY_API_VERSION;
+ return org.apache.airavata.registry.api.registry_apiConstants.REGISTRY_API_VERSION;
}
/**
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/SharingRegistryServerHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/SharingRegistryServerHandler.java
index f81c10b593..781b9d7637 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/SharingRegistryServerHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/SharingRegistryServerHandler.java
@@ -21,24 +21,23 @@ package org.apache.airavata.api.thrift.handler;
import java.util.List;
import org.apache.airavata.sharing.models.*;
-import org.apache.airavata.sharing.service.cpi.SharingRegistryService;
-import org.apache.airavata.sharing.service.cpi.sharing_cpiConstants;
import org.springframework.stereotype.Component;
+import org.apache.airavata.service.SharingRegistryService;
@Component
-public class SharingRegistryServerHandler implements SharingRegistryService.Iface {
- private final org.apache.airavata.service.SharingRegistryService sharingRegistryService;
+public class SharingRegistryServerHandler implements org.apache.airavata.sharing.service.cpi.SharingRegistryService.Iface {
+ private final SharingRegistryService sharingRegistryService;
- public SharingRegistryServerHandler(org.apache.airavata.service.SharingRegistryService sharingRegistryService) {
+ public SharingRegistryServerHandler(SharingRegistryService sharingRegistryService) {
this.sharingRegistryService = sharingRegistryService;
}
public static String OWNER_PERMISSION_NAME =
- org.apache.airavata.service.SharingRegistryService.OWNER_PERMISSION_NAME;
+ SharingRegistryService.OWNER_PERMISSION_NAME;
@Override
public String getAPIVersion() {
- return sharing_cpiConstants.SHARING_CPI_VERSION;
+ return org.apache.airavata.sharing.service.cpi.sharing_cpiConstants.SHARING_CPI_VERSION;
}
/**
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/TenantProfileServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/TenantProfileServiceHandler.java
index 59a41e8cd2..dc87104bbc 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/TenantProfileServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/TenantProfileServiceHandler.java
@@ -25,10 +25,9 @@ import org.apache.airavata.model.error.AiravataSystemException;
import org.apache.airavata.model.error.AuthorizationException;
import org.apache.airavata.model.security.AuthzToken;
import org.apache.airavata.model.workspace.Gateway;
-import org.apache.airavata.profile.tenant.cpi.TenantProfileService;
import org.apache.airavata.profile.tenant.cpi.exception.TenantProfileServiceException;
-import org.apache.airavata.profile.tenant.cpi.profile_tenant_cpiConstants;
import org.apache.airavata.security.interceptor.SecurityCheck;
+import org.apache.airavata.service.TenantProfileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -37,20 +36,20 @@ import org.springframework.stereotype.Component;
* Created by goshenoy on 3/6/17.
*/
@Component
-public class TenantProfileServiceHandler implements TenantProfileService.Iface {
+public class TenantProfileServiceHandler implements org.apache.airavata.profile.tenant.cpi.TenantProfileService.Iface {
private static final Logger logger = LoggerFactory.getLogger(TenantProfileServiceHandler.class);
- private final org.apache.airavata.service.TenantProfileService tenantProfileService;
+ private final TenantProfileService tenantProfileService;
- public TenantProfileServiceHandler(org.apache.airavata.service.TenantProfileService tenantProfileService) {
+ public TenantProfileServiceHandler(TenantProfileService tenantProfileService) {
this.tenantProfileService = tenantProfileService;
logger.debug("Initializing TenantProfileServiceHandler");
}
@Override
public String getAPIVersion() throws AiravataSystemException {
- return profile_tenant_cpiConstants.TENANT_PROFILE_CPI_VERSION;
+ return org.apache.airavata.profile.tenant.cpi.profile_tenant_cpiConstants.TENANT_PROFILE_CPI_VERSION;
}
@Override
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/UserProfileServiceHandler.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/UserProfileServiceHandler.java
index fbb72566ab..6e7ac93284 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/UserProfileServiceHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/handler/UserProfileServiceHandler.java
@@ -26,7 +26,6 @@ import org.apache.airavata.model.security.AuthzToken;
import org.apache.airavata.model.user.UserProfile;
import org.apache.airavata.profile.iam.admin.services.cpi.exception.IamAdminServicesException;
import org.apache.airavata.profile.user.cpi.exception.UserProfileServiceException;
-import org.apache.airavata.profile.user.cpi.profile_user_cpiConstants;
import org.apache.airavata.security.interceptor.SecurityCheck;
import org.springframework.stereotype.Component;
@@ -41,7 +40,7 @@ public class UserProfileServiceHandler implements org.apache.airavata.profile.us
@Override
public String getAPIVersion() throws AiravataSystemException {
- return profile_user_cpiConstants.USER_PROFILE_CPI_VERSION;
+ return org.apache.airavata.profile.user.cpi.profile_user_cpiConstants.USER_PROFILE_CPI_VERSION;
}
@Override
diff --git a/airavata-api/src/main/java/org/apache/airavata/api/thrift/server/SharingRegistryServer.java b/airavata-api/src/main/java/org/apache/airavata/api/thrift/server/SharingRegistryServer.java
index 34099b2697..c6116a93e5 100644
--- a/airavata-api/src/main/java/org/apache/airavata/api/thrift/server/SharingRegistryServer.java
+++ b/airavata-api/src/main/java/org/apache/airavata/api/thrift/server/SharingRegistryServer.java
@@ -27,8 +27,6 @@ import org.apache.airavata.config.AiravataServerProperties;
import org.apache.airavata.sharing.messaging.SharingServiceDBEventMessagingFactory;
import org.apache.airavata.sharing.models.SharingRegistryException;
import org.apache.airavata.sharing.service.cpi.SharingRegistryService;
-// Unused import - commented out
-// import org.apache.airavata.sharing.utils.SharingRegistryDBInitConfig;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.transport.TSSLTransportFactory;
@@ -82,8 +80,7 @@ public class SharingRegistryServer implements IServer {
final int serverPort = properties.services.sharing.serverPort;
// SharingRegistryServerHandler doesn't need DBInitConfig anymore - it's a Spring bean
SharingRegistryServerHandler handler = applicationContext.getBean(SharingRegistryServerHandler.class);
- SharingRegistryService.Processor<SharingRegistryServerHandler> processor =
- new SharingRegistryService.Processor<>(handler);
+ var processor = new SharingRegistryService.Processor<>(handler);
TServerTransport serverTransport;
TThreadPoolServer.Args options;
@@ -159,6 +156,10 @@ public class SharingRegistryServer implements IServer {
start();
}
+ /**
+ * Configure the server. Required by IServer interface.
+ * No configuration needed for SharingRegistryServer.
+ */
@Override
public void configure() throws Exception {}
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/exception/ErrorCodeGenerator.java b/airavata-api/src/main/java/org/apache/airavata/common/exception/ErrorCodeGenerator.java
new file mode 100644
index 0000000000..f0aff0af65
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/exception/ErrorCodeGenerator.java
@@ -0,0 +1,68 @@
+/**
+*
+* 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.common.exception;
+
+import java.util.UUID;
+
+/**
+ * Utility class for generating standardized error codes.
+ *
+ * <p>Error codes are used for tracking and correlating errors across the system.
+ * They provide a unique identifier for each error occurrence, making it easier
+ * to trace errors in logs and support requests.
+ */
+public class ErrorCodeGenerator {
+
+ private ErrorCodeGenerator() {
+ // Utility class - prevent instantiation
+ }
+
+ /**
+ * Generate a unique error code.
+ * Uses UUID to ensure uniqueness across the system.
+ *
+ * @return A unique error code string
+ */
+ public static String generateErrorCode() {
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * Generate an error code with a prefix for categorization.
+ *
+ * @param prefix The prefix to categorize the error (e.g., "EXP", "PROC", "TASK")
+ * @return A unique error code with prefix
+ */
+ public static String generateErrorCode(String prefix) {
+ return String.format("%s-%s", prefix, UUID.randomUUID().toString());
+ }
+
+ /**
+ * Generate an error code with prefix and timestamp.
+ *
+ * @param prefix The prefix to categorize the error
+ * @return A unique error code with prefix and timestamp
+ */
+ public static String generateErrorCodeWithTimestamp(String prefix) {
+ long timestamp = System.currentTimeMillis();
+ return String.format("%s-%d-%s", prefix, timestamp, UUID.randomUUID().toString().substring(0, 8));
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/exception/ExceptionHandlerUtil.java b/airavata-api/src/main/java/org/apache/airavata/common/exception/ExceptionHandlerUtil.java
new file mode 100644
index 0000000000..4e53d90146
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/exception/ExceptionHandlerUtil.java
@@ -0,0 +1,149 @@
+/**
+*
+* 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.common.exception;
+
+import org.apache.airavata.common.logging.LoggingUtil;
+import org.apache.airavata.model.error.AiravataErrorType;
+import org.apache.airavata.model.error.AiravataSystemException;
+import org.slf4j.Logger;
+
+/**
+ * Utility class for standardized exception handling patterns.
+ *
+ * <p>This class provides helper methods to ensure consistent exception handling:
+ * <ul>
+ * <li>Convert exceptions to AiravataSystemException with proper error types</li>
+ * <li>Log exceptions with context using MDC</li>
+ * <li>Wrap exceptions with appropriate error codes</li>
+ * <li>Provide standardized error message formatting</li>
+ * </ul>
+ */
+public class ExceptionHandlerUtil {
+
+ private ExceptionHandlerUtil() {
+ // Utility class - prevent instantiation
+ }
+
+ /**
+ * Handle an exception by logging it and converting to AiravataSystemException.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param errorType The Airavata error type
+ * @param exception The exception that occurred
+ * @return AiravataSystemException with the error details
+ */
+ public static AiravataSystemException handleException(
+ Logger logger, String operation, AiravataErrorType errorType, Throwable exception) {
+ String message = String.format("[%s] failed: %s", operation, exception.getMessage());
+ LoggingUtil.logError(logger, operation, exception.getMessage(), exception);
+
+ AiravataSystemException airavataException = new AiravataSystemException(errorType);
+ airavataException.setMessage(message);
+ airavataException.initCause(exception);
+ return airavataException;
+ }
+
+ /**
+ * Handle an exception with context information.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param errorType The Airavata error type
+ * @param exception The exception that occurred
+ * @param context Context parameters (key-value pairs)
+ * @return AiravataSystemException with the error details
+ */
+ public static AiravataSystemException handleExceptionWithContext(
+ Logger logger, String operation, AiravataErrorType errorType,
+ Throwable exception, java.util.Map<String, String> context) {
+ LoggingUtil.logErrorWithContext(logger, operation, exception.getMessage(), exception, context);
+
+ StringBuilder message = new StringBuilder();
+ message.append(String.format("[%s] failed: %s", operation, exception.getMessage()));
+ if (context != null && !context.isEmpty()) {
+ message.append(" | Context: ");
+ context.forEach((key, value) -> message.append(String.format("%s=%s, ", key, value)));
+ message.setLength(message.length() - 2);
+ }
+
+ AiravataSystemException airavataException = new AiravataSystemException(errorType);
+ airavataException.setMessage(message.toString());
+ airavataException.initCause(exception);
+ return airavataException;
+ }
+
+ /**
+ * Handle an exception with MDC context (experiment, gateway, process IDs).
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param errorType The Airavata error type
+ * @param exception The exception that occurred
+ * @param experimentId The experiment ID (optional)
+ * @param gatewayId The gateway ID (optional)
+ * @param processId The process ID (optional)
+ * @return AiravataSystemException with the error details
+ */
+ public static AiravataSystemException handleExceptionWithMDC(
+ Logger logger, String operation, AiravataErrorType errorType,
+ Throwable exception, String experimentId, String gatewayId, String processId) {
+ LoggingUtil.setExperimentContext(experimentId, gatewayId, processId);
+ try {
+ return handleException(logger, operation, errorType, exception);
+ } finally {
+ LoggingUtil.clearContext();
+ }
+ }
+
+ /**
+ * Wrap a generic exception as AiravataSystemException with a specific error type.
+ *
+ * @param errorType The Airavata error type
+ * @param message The error message
+ * @param cause The underlying exception
+ * @return AiravataSystemException
+ */
+ public static AiravataSystemException wrapAsAiravataException(
+ AiravataErrorType errorType, String message, Throwable cause) {
+ AiravataSystemException exception = new AiravataSystemException(errorType);
+ exception.setMessage(message);
+ if (cause != null) {
+ exception.initCause(cause);
+ }
+ return exception;
+ }
+
+ /**
+ * Create an AiravataSystemException with an error code.
+ *
+ * @param errorType The Airavata error type
+ * @param message The error message
+ * @param errorCode The error code (generated by ErrorCodeGenerator)
+ * @param cause The underlying exception
+ * @return AiravataSystemException
+ */
+ public static AiravataSystemException createExceptionWithErrorCode(
+ AiravataErrorType errorType, String message, String errorCode, Throwable cause) {
+ String messageWithCode = String.format("Error Code: %s, %s", errorCode, message);
+ return wrapAsAiravataException(errorType, messageWithCode, cause);
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/logging/LoggingUtil.java b/airavata-api/src/main/java/org/apache/airavata/common/logging/LoggingUtil.java
new file mode 100644
index 0000000000..dfe2e1f631
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/logging/LoggingUtil.java
@@ -0,0 +1,247 @@
+/**
+*
+* 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.common.logging;
+
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.MDC;
+
+/**
+ * Utility class for standardized logging patterns across the Airavata API.
+ *
+ * <p>This class provides helper methods to ensure consistent logging:
+ * <ul>
+ * <li>Always include exceptions in error logs</li>
+ * <li>Use structured logging with MDC for correlation IDs</li>
+ * <li>Standardize log message format: [Operation] failed: [reason]</li>
+ * <li>Provide context-aware logging methods</li>
+ * </ul>
+ *
+ * <p>Usage example:
+ * <pre>
+ * LoggingUtil.logError(logger, "Experiment launch", "Failed to validate experiment", exception);
+ * LoggingUtil.logErrorWithContext(logger, "Process execution", "Task failed", exception,
+ * Map.of("processId", processId, "taskId", taskId));
+ * </pre>
+ */
+public class LoggingUtil {
+
+ private LoggingUtil() {
+ // Utility class - prevent instantiation
+ }
+
+ /**
+ * Log an error with standardized format: [Operation] failed: [reason]
+ * Always includes the exception in the log.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed (e.g., "Experiment launch", "Process execution")
+ * @param reason The reason for the error
+ * @param exception The exception that occurred (may be null)
+ */
+ public static void logError(Logger logger, String operation, String reason, Throwable exception) {
+ String message = String.format("[%s] failed: %s", operation, reason);
+ if (exception != null) {
+ logger.error(message, exception);
+ } else {
+ logger.error(message);
+ }
+ }
+
+ /**
+ * Log an error with context information from MDC.
+ * The MDC context is automatically included in the log output.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param reason The reason for the error
+ * @param exception The exception that occurred (may be null)
+ */
+ public static void logErrorWithMDC(Logger logger, String operation, String reason, Throwable exception) {
+ logError(logger, operation, reason, exception);
+ }
+
+ /**
+ * Log an error with additional context parameters.
+ * Context parameters are included in the log message for better traceability.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param reason The reason for the error
+ * @param exception The exception that occurred (may be null)
+ * @param context Context parameters to include in the log message (key-value pairs)
+ */
+ public static void logErrorWithContext(Logger logger, String operation, String reason,
+ Throwable exception, java.util.Map<String, String> context) {
+ StringBuilder message = new StringBuilder();
+ message.append(String.format("[%s] failed: %s", operation, reason));
+
+ if (context != null && !context.isEmpty()) {
+ message.append(" | Context: ");
+ context.forEach((key, value) ->
+ message.append(String.format("%s=%s, ", key, value)));
+ // Remove trailing comma and space
+ message.setLength(message.length() - 2);
+ }
+
+ if (exception != null) {
+ logger.error(message.toString(), exception);
+ } else {
+ logger.error(message.toString());
+ }
+ }
+
+ /**
+ * Log a warning with standardized format: [Operation] warning: [message]
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param message The warning message
+ */
+ public static void logWarning(Logger logger, String operation, String message) {
+ logger.warn(String.format("[%s] warning: %s", operation, message));
+ }
+
+ /**
+ * Log a warning with context information.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param message The warning message
+ * @param context Context parameters to include in the log message
+ */
+ public static void logWarningWithContext(Logger logger, String operation, String message,
+ java.util.Map<String, String> context) {
+ StringBuilder logMessage = new StringBuilder();
+ logMessage.append(String.format("[%s] warning: %s", operation, message));
+
+ if (context != null && !context.isEmpty()) {
+ logMessage.append(" | Context: ");
+ context.forEach((key, value) ->
+ logMessage.append(String.format("%s=%s, ", key, value)));
+ logMessage.setLength(logMessage.length() - 2);
+ }
+
+ logger.warn(logMessage.toString());
+ }
+
+ /**
+ * Log an info message with standardized format: [Operation]: [message]
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param message The info message
+ */
+ public static void logInfo(Logger logger, String operation, String message) {
+ logger.info(String.format("[%s]: %s", operation, message));
+ }
+
+ /**
+ * Log an info message with context information.
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param message The info message
+ * @param context Context parameters to include in the log message
+ */
+ public static void logInfoWithContext(Logger logger, String operation, String message,
+ java.util.Map<String, String> context) {
+ StringBuilder logMessage = new StringBuilder();
+ logMessage.append(String.format("[%s]: %s", operation, message));
+
+ if (context != null && !context.isEmpty()) {
+ logMessage.append(" | Context: ");
+ context.forEach((key, value) ->
+ logMessage.append(String.format("%s=%s, ", key, value)));
+ logMessage.setLength(logMessage.length() - 2);
+ }
+
+ logger.info(logMessage.toString());
+ }
+
+ /**
+ * Log a debug message with standardized format: [Operation]: [message]
+ *
+ * @param logger The logger instance
+ * @param operation The operation being performed
+ * @param message The debug message
+ */
+ public static void logDebug(Logger logger, String operation, String message) {
+ logger.debug(String.format("[%s]: %s", operation, message));
+ }
+
+ /**
+ * Set MDC context for experiment-related operations.
+ * This helps with log correlation and tracing.
+ *
+ * @param experimentId The experiment ID
+ * @param gatewayId The gateway ID (optional, may be null)
+ * @param processId The process ID (optional, may be null)
+ */
+ public static void setExperimentContext(String experimentId, String gatewayId, String processId) {
+ if (experimentId != null) {
+ MDC.put(MDCConstants.EXPERIMENT_ID, experimentId);
+ }
+ if (gatewayId != null) {
+ MDC.put(MDCConstants.GATEWAY_ID, gatewayId);
+ }
+ if (processId != null) {
+ MDC.put(MDCConstants.PROCESS_ID, processId);
+ }
+ }
+
+ /**
+ * Clear MDC context.
+ * Should be called at the end of request processing or in finally blocks.
+ */
+ public static void clearContext() {
+ MDC.clear();
+ }
+
+ /**
+ * Execute a runnable with MDC context preserved.
+ * Useful for async operations where MDC context might be lost.
+ *
+ * @param runnable The runnable to execute
+ * @return A wrapped runnable that preserves MDC context
+ */
+ public static Runnable withMDC(Runnable runnable) {
+ Map<String, String> mdc = MDC.getCopyOfContextMap();
+ return () -> {
+ Map<String, String> oldMdc = MDC.getCopyOfContextMap();
+
+ if (mdc == null) {
+ MDC.clear();
+ } else {
+ MDC.setContextMap(mdc);
+ }
+ try {
+ runnable.run();
+ } finally {
+ if (oldMdc == null) {
+ MDC.clear();
+ } else {
+ MDC.setContextMap(oldMdc);
+ }
+ }
+ };
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/logging/MDCUtil.java b/airavata-api/src/main/java/org/apache/airavata/common/logging/MDCUtil.java
deleted file mode 100644
index aa43edd06c..0000000000
--- a/airavata-api/src/main/java/org/apache/airavata/common/logging/MDCUtil.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
-*
-* 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.common.logging;
-
-import java.util.Map;
-import org.slf4j.MDC;
-
-public class MDCUtil {
- public static Runnable wrapWithMDC(Runnable r) {
- Map<String, String> mdc = MDC.getCopyOfContextMap();
- return () -> {
- Map<String, String> oldMdc = MDC.getCopyOfContextMap();
-
- if (mdc == null) {
- MDC.clear();
- } else {
- MDC.setContextMap(mdc);
- }
- try {
- r.run();
- } finally {
- if (oldMdc == null) {
- MDC.clear();
- } else {
- MDC.setContextMap(oldMdc);
- }
- }
- };
- }
-}
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/repositories/AbstractRepository.java b/airavata-api/src/main/java/org/apache/airavata/common/repositories/AbstractRepository.java
new file mode 100644
index 0000000000..a4b92f4b97
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/repositories/AbstractRepository.java
@@ -0,0 +1,173 @@
+/**
+*
+* 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.common.repositories;
+
+import com.github.dozermapper.core.Mapper;
+import jakarta.persistence.EntityManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Common base class for repository implementations across Airavata modules.
+ *
+ * <p>This class provides core CRUD operations that are common across all repository
+ * implementations. Module-specific repositories should extend this class and add
+ * module-specific query methods and exception handling.
+ *
+ * <p>The class uses a generic type system:
+ * <ul>
+ * <li>T - The Thrift model type (e.g., ExperimentModel, ProcessModel)</li>
+ * <li>E - The JPA entity type (e.g., ExperimentEntity, ProcessEntity)</li>
+ * <li>Id - The primary key type (e.g., String, ProcessPK)</li>
+ * </ul>
+ *
+ * <p>Subclasses must implement:
+ * <ul>
+ * <li>{@link #getMapper()} - Returns the Dozer mapper instance</li>
+ * <li>{@link #getEntityManager()} - Returns the EntityManager for this persistence unit</li>
+ * </ul>
+ *
+ * @param <T> The Thrift model type
+ * @param <E> The JPA entity type
+ * @param <Id> The primary key type
+ */
+public abstract class AbstractRepository<T, E, Id> {
+ protected static final Logger logger = LoggerFactory.getLogger(AbstractRepository.class);
+
+ protected final Class<T> thriftGenericClass;
+ protected final Class<E> dbEntityGenericClass;
+
+ /**
+ * Constructor for the abstract repository.
+ *
+ * @param thriftGenericClass The Thrift model class
+ * @param dbEntityGenericClass The JPA entity class
+ */
+ protected AbstractRepository(Class<T> thriftGenericClass, Class<E> dbEntityGenericClass) {
+ this.thriftGenericClass = thriftGenericClass;
+ this.dbEntityGenericClass = dbEntityGenericClass;
+ }
+
+ /**
+ * Get the Dozer mapper instance for converting between Thrift models and entities.
+ *
+ * @return The mapper instance
+ */
+ protected abstract Mapper getMapper();
+
+ /**
+ * Get the EntityManager for this persistence unit.
+ * Each module should provide its own EntityManager implementation.
+ *
+ * @return The EntityManager instance
+ */
+ protected abstract EntityManager getEntityManager();
+
+ /**
+ * Create a new entity. This is equivalent to update() for most implementations.
+ *
+ * @param t The Thrift model to persist
+ * @return The persisted Thrift model
+ */
+ @Transactional
+ public T create(T t) {
+ return update(t);
+ }
+
+ /**
+ * Update or create an entity.
+ *
+ * @param t The Thrift model to persist
+ * @return The persisted Thrift model
+ */
+ @Transactional
+ public T update(T t) {
+ E entity = mapToEntity(t);
+ return mergeEntity(entity);
+ }
+
+ /**
+ * Map a Thrift model to a JPA entity.
+ *
+ * @param t The Thrift model
+ * @return The JPA entity
+ */
+ protected E mapToEntity(T t) {
+ return getMapper().map(t, dbEntityGenericClass);
+ }
+
+ /**
+ * Merge an entity into the persistence context and map back to Thrift model.
+ *
+ * @param entity The JPA entity
+ * @return The persisted Thrift model
+ */
+ protected T mergeEntity(E entity) {
+ EntityManager em = getEntityManager();
+ E persistedCopy = em.merge(entity);
+ return getMapper().map(persistedCopy, thriftGenericClass);
+ }
+
+ /**
+ * Delete an entity by its primary key.
+ *
+ * @param id The primary key
+ * @return true if the entity was deleted, false if it didn't exist
+ */
+ @Transactional
+ public boolean delete(Id id) {
+ EntityManager em = getEntityManager();
+ E entity = em.find(dbEntityGenericClass, id);
+ if (entity != null) {
+ em.remove(entity);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve an entity by its primary key.
+ *
+ * @param id The primary key
+ * @return The Thrift model, or null if not found
+ */
+ @Transactional(readOnly = true)
+ public T get(Id id) {
+ EntityManager em = getEntityManager();
+ E entity = em.find(dbEntityGenericClass, id);
+ if (entity == null) {
+ return null;
+ }
+ return getMapper().map(entity, thriftGenericClass);
+ }
+
+ /**
+ * Check if an entity exists by its primary key.
+ *
+ * @param id The primary key
+ * @return true if the entity exists, false otherwise
+ */
+ @Transactional(readOnly = true)
+ public boolean isExists(Id id) {
+ return get(id) != null;
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationResult.java b/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationResult.java
new file mode 100644
index 0000000000..c3d378a6f2
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationResult.java
@@ -0,0 +1,148 @@
+/**
+*
+* 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.common.validation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents the result of a validation operation.
+ *
+ * <p>Contains information about whether validation passed or failed,
+ * and a list of validation errors if any occurred.
+ */
+public class ValidationResult {
+ private boolean valid;
+ private List<ValidationError> errors;
+
+ public ValidationResult() {
+ this.valid = true;
+ this.errors = new ArrayList<>();
+ }
+
+ public ValidationResult(boolean valid) {
+ this.valid = valid;
+ this.errors = new ArrayList<>();
+ }
+
+ /**
+ * Check if validation passed.
+ *
+ * @return true if valid, false otherwise
+ */
+ public boolean isValid() {
+ return valid;
+ }
+
+ /**
+ * Set the validation status.
+ *
+ * @param valid true if valid, false otherwise
+ */
+ public void setValid(boolean valid) {
+ this.valid = valid;
+ }
+
+ /**
+ * Get the list of validation errors.
+ *
+ * @return List of validation errors
+ */
+ public List<ValidationError> getErrors() {
+ return errors;
+ }
+
+ /**
+ * Set the list of validation errors.
+ *
+ * @param errors List of validation errors
+ */
+ public void setErrors(List<ValidationError> errors) {
+ this.errors = errors != null ? errors : new ArrayList<>();
+ }
+
+ /**
+ * Add a validation error.
+ *
+ * @param field The field that failed validation
+ * @param message The error message
+ */
+ public void addError(String field, String message) {
+ this.valid = false;
+ this.errors.add(new ValidationError(field, message));
+ }
+
+ /**
+ * Add a validation error.
+ *
+ * @param error The validation error
+ */
+ public void addError(ValidationError error) {
+ this.valid = false;
+ this.errors.add(error);
+ }
+
+ /**
+ * Check if there are any errors.
+ *
+ * @return true if there are errors, false otherwise
+ */
+ public boolean hasErrors() {
+ return !errors.isEmpty();
+ }
+
+ /**
+ * Represents a single validation error.
+ */
+ public static class ValidationError {
+ private String field;
+ private String message;
+
+ public ValidationError() {
+ }
+
+ public ValidationError(String field, String message) {
+ this.field = field;
+ this.message = message;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public void setField(String field) {
+ this.field = field;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ValidationError{field='%s', message='%s'}", field, message);
+ }
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationService.java b/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationService.java
new file mode 100644
index 0000000000..43f7896ab9
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/common/validation/ValidationService.java
@@ -0,0 +1,141 @@
+/**
+*
+* 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.common.validation;
+
+import org.apache.airavata.common.utils.NameValidator;
+
+/**
+ * Service for performing common validation operations.
+ *
+ * <p>This service provides standardized validation methods that can be used
+ * across the Airavata API. It centralizes common validation logic and provides
+ * a consistent interface for validation operations.
+ */
+public class ValidationService {
+
+ /**
+ * Validate that a string is not null, empty, or blank.
+ *
+ * @param value The string to validate
+ * @param fieldName The name of the field (for error messages)
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validateRequiredString(String value, String fieldName, ValidationResult result) {
+ if (value == null || value.trim().isEmpty()) {
+ result.addError(fieldName, String.format("%s is required and cannot be empty", fieldName));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate that a string matches a name pattern (alphanumeric, underscore, dot).
+ *
+ * @param value The string to validate
+ * @param fieldName The name of the field (for error messages)
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validateName(String value, String fieldName, ValidationResult result) {
+ if (!NameValidator.validate(value)) {
+ result.addError(fieldName,
+ String.format("%s must start with a letter and contain only letters, numbers, underscores, and dots", fieldName));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate that a string is within a specified length range.
+ *
+ * @param value The string to validate
+ * @param fieldName The name of the field
+ * @param minLength Minimum length (inclusive)
+ * @param maxLength Maximum length (inclusive)
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validateLength(String value, String fieldName, int minLength, int maxLength, ValidationResult result) {
+ if (value == null) {
+ result.addError(fieldName, String.format("%s cannot be null", fieldName));
+ return false;
+ }
+ int length = value.length();
+ if (length < minLength || length > maxLength) {
+ result.addError(fieldName,
+ String.format("%s must be between %d and %d characters long", fieldName, minLength, maxLength));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate that an object is not null.
+ *
+ * @param value The object to validate
+ * @param fieldName The name of the field
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validateNotNull(Object value, String fieldName, ValidationResult result) {
+ if (value == null) {
+ result.addError(fieldName, String.format("%s cannot be null", fieldName));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate that a number is within a specified range.
+ *
+ * @param value The number to validate
+ * @param fieldName The name of the field
+ * @param min Minimum value (inclusive)
+ * @param max Maximum value (inclusive)
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validateRange(long value, String fieldName, long min, long max, ValidationResult result) {
+ if (value < min || value > max) {
+ result.addError(fieldName,
+ String.format("%s must be between %d and %d", fieldName, min, max));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validate that a number is positive (greater than zero).
+ *
+ * @param value The number to validate
+ * @param fieldName The name of the field
+ * @param result The validation result to add errors to
+ * @return true if valid, false otherwise
+ */
+ public static boolean validatePositive(long value, String fieldName, ValidationResult result) {
+ if (value <= 0) {
+ result.addError(fieldName, String.format("%s must be greater than zero", fieldName));
+ return false;
+ }
+ return true;
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
index 397588880b..4a8549a01c 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/aws/AWSCompletingTask.java
@@ -55,6 +55,10 @@ public class AWSCompletingTask extends AiravataTask {
return onSuccess("Process " + getProcessId() + " successfully completed");
}
+ /**
+ * Called when the task is cancelled.
+ * No cleanup needed for AWS completing tasks.
+ */
@Override
public void onCancel(TaskContext taskContext) {}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/RemoteJobCancellationTask.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/RemoteJobCancellationTask.java
index 6ca1394b9f..f519ce2f8a 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/RemoteJobCancellationTask.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/RemoteJobCancellationTask.java
@@ -197,8 +197,8 @@ public class RemoteJobCancellationTask extends AiravataTask {
ex);
}
- // TODO this is temporary fix. Remove this line when the schedulers are configured to notify when an job
- // is externally cancelled
+ // TODO: Remove this temporary fix once schedulers are configured to notify when a job is externally cancelled
+ // This is a workaround until proper job cancellation notification is implemented
// forcefully make the job state as cancelled as some schedulers do not notify when the job is
// cancelled.
saveAndPublishJobStatus(
@@ -219,6 +219,10 @@ public class RemoteJobCancellationTask extends AiravataTask {
}
}
+ /**
+ * Called when the task is cancelled.
+ * Cancellation logic is handled in the onRun method's catch block.
+ */
@Override
public void onCancel(TaskContext taskContext) {}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/WorkflowCancellationTask.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/WorkflowCancellationTask.java
index 65cd130fc0..d7da8a7f47 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/WorkflowCancellationTask.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/cancel/WorkflowCancellationTask.java
@@ -147,6 +147,10 @@ public class WorkflowCancellationTask extends AbstractTask {
}
}
+ /**
+ * Called when the task is cancelled.
+ * No cleanup needed for workflow cancellation tasks.
+ */
@Override
public void onCancel() {}
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/parsing/DataParsingTask.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/parsing/DataParsingTask.java
index f7eca334dc..b0fc421bf2 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/parsing/DataParsingTask.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/parsing/DataParsingTask.java
@@ -260,6 +260,10 @@ public class DataParsingTask extends AbstractTask {
}
}
+ /**
+ * Called when the task is cancelled.
+ * No cleanup needed for data parsing tasks.
+ */
@Override
public void onCancel() {}
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/DefaultJobSubmissionTask.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/DefaultJobSubmissionTask.java
index 9f70f28bd2..c243fb82c4 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/DefaultJobSubmissionTask.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/DefaultJobSubmissionTask.java
@@ -296,6 +296,10 @@ public class DefaultJobSubmissionTask extends JobSubmissionTask {
return jobId;
}
+ /**
+ * Called when the task is cancelled.
+ * No cleanup needed for job submission tasks.
+ */
@Override
public void onCancel(TaskContext taskContext) {}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/app/parser/AiravataCustomCommandOutputParser.java b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/app/parser/AiravataCustomCommandOutputParser.java
index b05350913c..6f8b7ae4dc 100644
--- a/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/app/parser/AiravataCustomCommandOutputParser.java
+++ b/airavata-api/src/main/java/org/apache/airavata/helix/impl/task/submission/config/app/parser/AiravataCustomCommandOutputParser.java
@@ -25,6 +25,15 @@ import org.apache.airavata.model.status.JobStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Placeholder implementation of OutputParser for Airavata custom command output parsing.
+ *
+ * <p>This class is currently a stub implementation where all methods throw
+ * UnsupportedOperationException. It is used by CloudJobManagerConfiguration but
+ * requires implementation to be functional.
+ *
+ * <p>TODO: Implement the parsing logic for Airavata custom command output format.
+ */
public class AiravataCustomCommandOutputParser implements OutputParser {
private static final Logger log = LoggerFactory.getLogger(AiravataCustomCommandOutputParser.class);
diff --git a/airavata-api/src/main/java/org/apache/airavata/messaging/client/RabbitMQListener.java b/airavata-api/src/main/java/org/apache/airavata/messaging/client/RabbitMQListener.java
index fbf625b718..855b9547ad 100644
--- a/airavata-api/src/main/java/org/apache/airavata/messaging/client/RabbitMQListener.java
+++ b/airavata-api/src/main/java/org/apache/airavata/messaging/client/RabbitMQListener.java
@@ -88,13 +88,4 @@ public class RabbitMQListener {
}
}
- // Unused enum - commented out
- /*
- private enum LEVEL {
- ALL,
- GATEWAY,
- EXPERIMENT,
- JOB;
- }
- */
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/monitor/email/parser/PBSEmailParser.java b/airavata-api/src/main/java/org/apache/airavata/monitor/email/parser/PBSEmailParser.java
index 00d9edaf9e..a3a08293e4 100644
--- a/airavata-api/src/main/java/org/apache/airavata/monitor/email/parser/PBSEmailParser.java
+++ b/airavata-api/src/main/java/org/apache/airavata/monitor/email/parser/PBSEmailParser.java
@@ -77,7 +77,8 @@ public class PBSEmailParser implements EmailParser {
case EXECUTION_TERMINATED:
int exitStatus = getExitStatus(content);
if (exitStatus == 0) {
- // TODO - Remove rabbitmq client script line from the script.
+ // TODO: Remove rabbitmq client script line from the script
+ // This is a workaround that should be removed once script generation is updated
return JobState.COMPLETE;
} else if (exitStatus == 271) {
return JobState.CANCELED;
diff --git a/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultDeserializer.java b/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultDeserializer.java
index 4ad03112e2..971b263420 100644
--- a/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultDeserializer.java
+++ b/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultDeserializer.java
@@ -25,6 +25,10 @@ import org.apache.airavata.monitor.JobStatusResult;
import org.apache.kafka.common.serialization.Deserializer;
public class JobStatusResultDeserializer implements Deserializer<JobStatusResult> {
+ /**
+ * Configure the deserializer. Required by Kafka Deserializer interface.
+ * No configuration needed for this deserializer.
+ */
@Override
public void configure(Map<String, ?> map, boolean b) {}
@@ -40,6 +44,10 @@ public class JobStatusResultDeserializer implements Deserializer<JobStatusResult
return jobStatusResult;
}
+ /**
+ * Close the deserializer. Required by Kafka Deserializer interface.
+ * No cleanup needed for this deserializer.
+ */
@Override
public void close() {}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultSerializer.java b/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultSerializer.java
index 7ebfaf5bfa..e7dc15a70a 100644
--- a/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultSerializer.java
+++ b/airavata-api/src/main/java/org/apache/airavata/monitor/kafka/JobStatusResultSerializer.java
@@ -25,6 +25,10 @@ import org.apache.kafka.common.serialization.Serializer;
public class JobStatusResultSerializer implements Serializer<JobStatusResult> {
+ /**
+ * Configure the serializer. Required by Kafka Serializer interface.
+ * No configuration needed for this serializer.
+ */
@Override
public void configure(Map<String, ?> map, boolean b) {}
@@ -36,6 +40,10 @@ public class JobStatusResultSerializer implements Serializer<JobStatusResult> {
return serializedData.getBytes();
}
+ /**
+ * Close the serializer. Required by Kafka Serializer interface.
+ * No cleanup needed for this serializer.
+ */
@Override
public void close() {}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/profile/utils/TenantManagementKeycloakImpl.java b/airavata-api/src/main/java/org/apache/airavata/profile/utils/TenantManagementKeycloakImpl.java
index 645b7ea660..e66966f71f 100644
--- a/airavata-api/src/main/java/org/apache/airavata/profile/utils/TenantManagementKeycloakImpl.java
+++ b/airavata-api/src/main/java/org/apache/airavata/profile/utils/TenantManagementKeycloakImpl.java
@@ -667,7 +667,8 @@ public class TenantManagementKeycloakImpl implements TenantManagementInterface {
}
}
- // TODO: this is needed for migrating from roles to group-based auth but after migration we can remove this
+ // TODO: Remove after migration to group-based auth is complete
+ // This method is needed for backward compatibility during migration from role-based to group-based authentication
@Override
public List<UserProfile> getUsersWithRole(PasswordCredential realmAdminCreds, String tenantId, String roleName)
throws IamAdminServicesException {
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/cpi/ReplicaCatalog.java b/airavata-api/src/main/java/org/apache/airavata/registry/cpi/ReplicaCatalog.java
index d7e5421b8c..f27df1bbac 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/cpi/ReplicaCatalog.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/cpi/ReplicaCatalog.java
@@ -24,32 +24,4 @@ Included for backwards compatibility
TODO: Remove interface once registry refactoring is complete
*/
public interface ReplicaCatalog extends DataProductInterface, DataReplicaLocationInterface {
- /*String schema = "airavata-dp";
-
- String registerDataProduct(DataProductModel product) throws ReplicaCatalogException;
-
- boolean removeDataProduct(String productUri) throws ReplicaCatalogException;
-
- boolean updateDataProduct(DataProductModel product) throws ReplicaCatalogException;
-
- DataProductModel getDataProduct(String productUri) throws ReplicaCatalogException;
-
- boolean isDataProductExists(String productUri) throws ReplicaCatalogException;
-
- String registerReplicaLocation(DataReplicaLocationModel dataReplicaLocationModel) throws ReplicaCatalogException;
-
- boolean removeReplicaLocation(String replicaId) throws ReplicaCatalogException;
-
- boolean updateReplicaLocation(DataReplicaLocationModel dataReplicaLocationModel) throws ReplicaCatalogException;
-
- DataReplicaLocationModel getReplicaLocation(String replicaId) throws ReplicaCatalogException;
-
- List<DataReplicaLocationModel> getAllReplicaLocations(String productUri) throws ReplicaCatalogException;
-
- DataProductModel getParentDataProduct(String productUri) throws ReplicaCatalogException;
-
- List<DataProductModel> getChildDataProducts(String productUri) throws ReplicaCatalogException;
-
- List<DataProductModel> searchDataProductsByName(String gatewayId, String userId, String productName,
- int limit, int offset) throws ReplicaCatalogException;*/
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/BaseErrorService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/BaseErrorService.java
new file mode 100644
index 0000000000..1dafbca9fe
--- /dev/null
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/BaseErrorService.java
@@ -0,0 +1,119 @@
+/**
+*
+* 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.services;
+
+import com.github.dozermapper.core.Mapper;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.airavata.model.commons.ErrorModel;
+import org.apache.airavata.registry.exceptions.RegistryException;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Base service class for error management operations.
+ * Provides common functionality for adding, updating, and retrieving errors
+ * associated with different entity types (Process, Task, Experiment).
+ *
+ * @param <TEntity> The error entity type (e.g., ProcessErrorEntity, TaskErrorEntity)
+ * @param <TRepository> The repository interface extending JpaRepository
+ * @param <TPK> The primary key type for the entity
+ */
+public abstract class BaseErrorService<TEntity, TRepository extends JpaRepository<TEntity, TPK>, TPK> {
+
+ protected final TRepository repository;
+ protected final Mapper mapper;
+
+ /**
+ * Functional interface to set the parent entity ID on the error entity.
+ * For example: entity.setProcessId(parentId)
+ */
+ protected abstract BiConsumer<TEntity, String> getParentIdSetter();
+
+ /**
+ * Functional interface to retrieve errors by parent entity ID.
+ * For example: repository.findByProcessId(parentId)
+ */
+ protected abstract Function<String, List<TEntity>> getFindByParentIdFunction();
+
+ /**
+ * Get the entity class for Dozer mapping.
+ */
+ protected abstract Class<TEntity> getEntityClass();
+
+ /**
+ * Functional interface to extract the error ID from the entity.
+ * For example: entity.getErrorId()
+ */
+ protected abstract Function<TEntity, String> getErrorIdExtractor();
+
+ protected BaseErrorService(TRepository repository, Mapper mapper) {
+ this.repository = repository;
+ this.mapper = mapper;
+ }
+
+ /**
+ * Add an error associated with a parent entity.
+ *
+ * @param error The error model to persist
+ * @param parentId The ID of the parent entity (processId, taskId, or experimentId)
+ * @return The ID of the saved error entity
+ * @throws RegistryException if the operation fails
+ */
+ @Transactional
+ public String addError(ErrorModel error, String parentId) throws RegistryException {
+ TEntity entity = mapper.map(error, getEntityClass());
+ getParentIdSetter().accept(entity, parentId);
+ TEntity saved = repository.save(entity);
+ return getErrorIdExtractor().apply(saved);
+ }
+
+ /**
+ * Update an existing error associated with a parent entity.
+ *
+ * @param error The error model with updated information
+ * @param parentId The ID of the parent entity
+ * @throws RegistryException if the operation fails
+ */
+ @Transactional
+ public void updateError(ErrorModel error, String parentId) throws RegistryException {
+ TEntity entity = mapper.map(error, getEntityClass());
+ getParentIdSetter().accept(entity, parentId);
+ repository.save(entity);
+ }
+
+ /**
+ * Retrieve all errors associated with a parent entity.
+ *
+ * @param parentId The ID of the parent entity
+ * @return List of error models
+ * @throws RegistryException if the operation fails
+ */
+ @Transactional(readOnly = true)
+ public List<ErrorModel> getErrors(String parentId) throws RegistryException {
+ List<TEntity> entities = getFindByParentIdFunction().apply(parentId);
+ return entities.stream()
+ .map(e -> mapper.map(e, ErrorModel.class))
+ .collect(Collectors.toList());
+ }
+}
+
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentErrorService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentErrorService.java
index 6908b0e30e..1ec932e33c 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentErrorService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/ExperimentErrorService.java
@@ -20,10 +20,11 @@
package org.apache.airavata.registry.services;
import com.github.dozermapper.core.Mapper;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
import org.apache.airavata.model.commons.ErrorModel;
import org.apache.airavata.registry.entities.expcatalog.ExperimentErrorEntity;
+import org.apache.airavata.registry.entities.expcatalog.ExperimentErrorPK;
import org.apache.airavata.registry.exceptions.RegistryException;
import org.apache.airavata.registry.repositories.expcatalog.ExperimentErrorRepository;
import org.springframework.stereotype.Service;
@@ -31,32 +32,63 @@ import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
-public class ExperimentErrorService {
- private final ExperimentErrorRepository experimentErrorRepository;
- private final Mapper mapper;
+public class ExperimentErrorService extends BaseErrorService<ExperimentErrorEntity, ExperimentErrorRepository, ExperimentErrorPK> {
public ExperimentErrorService(ExperimentErrorRepository experimentErrorRepository, Mapper mapper) {
- this.experimentErrorRepository = experimentErrorRepository;
- this.mapper = mapper;
+ super(experimentErrorRepository, mapper);
}
+ @Override
+ protected BiConsumer<ExperimentErrorEntity, String> getParentIdSetter() {
+ return ExperimentErrorEntity::setExperimentId;
+ }
+
+ @Override
+ protected Function<String, java.util.List<ExperimentErrorEntity>> getFindByParentIdFunction() {
+ return repository::findByExperimentId;
+ }
+
+ @Override
+ protected Class<ExperimentErrorEntity> getEntityClass() {
+ return ExperimentErrorEntity.class;
+ }
+
+ @Override
+ protected Function<ExperimentErrorEntity, String> getErrorIdExtractor() {
+ return ExperimentErrorEntity::getErrorId;
+ }
+
+ /**
+ * Add an experiment error.
+ *
+ * @param error The error model to persist
+ * @param experimentId The ID of the experiment
+ * @return The ID of the saved error entity
+ * @throws RegistryException if the operation fails
+ */
public String addExperimentError(ErrorModel error, String experimentId) throws RegistryException {
- ExperimentErrorEntity entity = mapper.map(error, ExperimentErrorEntity.class);
- entity.setExperimentId(experimentId);
- ExperimentErrorEntity saved = experimentErrorRepository.save(entity);
- return saved.getErrorId();
+ return addError(error, experimentId);
}
+ /**
+ * Update an experiment error.
+ *
+ * @param error The error model with updated information
+ * @param experimentId The ID of the experiment
+ * @throws RegistryException if the operation fails
+ */
public void updateExperimentError(ErrorModel error, String experimentId) throws RegistryException {
- ExperimentErrorEntity entity = mapper.map(error, ExperimentErrorEntity.class);
- entity.setExperimentId(experimentId);
- experimentErrorRepository.save(entity);
+ updateError(error, experimentId);
}
- public List<ErrorModel> getExperimentErrors(String experimentId) throws RegistryException {
- List<ExperimentErrorEntity> entities = experimentErrorRepository.findByExperimentId(experimentId);
- List<ErrorModel> result = new ArrayList<>();
- entities.forEach(e -> result.add(mapper.map(e, ErrorModel.class)));
- return result;
+ /**
+ * Retrieve all errors for an experiment.
+ *
+ * @param experimentId The ID of the experiment
+ * @return List of error models
+ * @throws RegistryException if the operation fails
+ */
+ public java.util.List<ErrorModel> getExperimentErrors(String experimentId) throws RegistryException {
+ return getErrors(experimentId);
}
}
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 e3fcacf109..9242e0fe98 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,7 +39,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@Transactional
public class ExperimentService {
private static final Logger logger = LoggerFactory.getLogger(ExperimentService.class);
@@ -53,6 +52,7 @@ public class ExperimentService {
this.mapper = mapper;
}
+ @Transactional
public String addExperiment(ExperimentModel experimentModel) throws RegistryException {
ExperimentStatus experimentStatus = new ExperimentStatus();
experimentStatus.setState(ExperimentState.CREATED);
@@ -66,16 +66,19 @@ public class ExperimentService {
return saveExperimentModelData(experimentModel);
}
+ @Transactional
public void updateExperiment(ExperimentModel updatedExperimentModel, String experimentId) throws RegistryException {
saveExperimentModelData(updatedExperimentModel);
}
+ @Transactional(readOnly = true)
public ExperimentModel getExperiment(String experimentId) throws RegistryException {
ExperimentEntity entity = experimentRepository.findById(experimentId).orElse(null);
if (entity == null) return null;
return mapper.map(entity, ExperimentModel.class);
}
+ @Transactional
public String addUserConfigurationData(UserConfigurationDataModel userConfigurationDataModel, String experimentId)
throws RegistryException {
ExperimentModel experimentModel = getExperiment(experimentId);
@@ -84,17 +87,20 @@ public class ExperimentService {
return experimentId;
}
+ @Transactional
public String updateUserConfigurationData(
UserConfigurationDataModel updatedUserConfigurationDataModel, String experimentId)
throws RegistryException {
return addUserConfigurationData(updatedUserConfigurationDataModel, experimentId);
}
+ @Transactional(readOnly = true)
public UserConfigurationDataModel getUserConfigurationData(String experimentId) throws RegistryException {
ExperimentModel experimentModel = getExperiment(experimentId);
return experimentModel.getUserConfigurationData();
}
+ @Transactional(readOnly = true)
public List<ExperimentModel> getExperimentList(
String gatewayId,
String fieldName,
@@ -126,10 +132,12 @@ public class ExperimentService {
return experimentModelList;
}
+ @Transactional(readOnly = true)
public boolean isExperimentExist(String experimentId) throws RegistryException {
return experimentRepository.existsById(experimentId);
}
+ @Transactional
public void removeExperiment(String experimentId) throws RegistryException {
experimentRepository.deleteById(experimentId);
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/GwyResourceProfileService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/GwyResourceProfileService.java
index e5fae84b5e..97c629ab81 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/GwyResourceProfileService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/GwyResourceProfileService.java
@@ -36,7 +36,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@Transactional
public class GwyResourceProfileService {
private final GwyResourceProfileRepository gwyResourceProfileRepository;
private final ComputeResourcePrefRepository computeResourcePrefRepository;
@@ -57,15 +56,18 @@ public class GwyResourceProfileService {
this.sshAccountProvisionerConfigurationRepository = sshAccountProvisionerConfigurationRepository;
}
+ @Transactional
public String addGatewayResourceProfile(GatewayResourceProfile gatewayResourceProfile) {
return updateGatewayResourceProfile(gatewayResourceProfile);
}
+ @Transactional
public void updateGatewayResourceProfile(String gatewayId, GatewayResourceProfile updatedProfile)
throws AppCatalogException {
updateGatewayResourceProfile(updatedProfile);
}
+ @Transactional
public String updateGatewayResourceProfile(GatewayResourceProfile gatewayResourceProfile) {
String gatewayId = gatewayResourceProfile.getGatewayID();
GatewayProfileEntity gatewayProfileEntity = mapper.map(gatewayResourceProfile, GatewayProfileEntity.class);
@@ -108,6 +110,7 @@ public class GwyResourceProfileService {
return persistedCopy.getGatewayId();
}
+ @Transactional(readOnly = true)
public GatewayResourceProfile getGatewayProfile(String gatewayId) {
GatewayProfileEntity entity =
gwyResourceProfileRepository.findById(gatewayId).orElse(null);
@@ -125,6 +128,7 @@ public class GwyResourceProfileService {
return gatewayResourceProfile;
}
+ @Transactional
public boolean removeGatewayResourceProfile(String gatewayId) throws AppCatalogException {
if (!gwyResourceProfileRepository.existsById(gatewayId)) {
return false;
@@ -133,6 +137,7 @@ public class GwyResourceProfileService {
return true;
}
+ @Transactional(readOnly = true)
public List<GatewayResourceProfile> getAllGatewayProfiles() {
List<GatewayProfileEntity> entities = gwyResourceProfileRepository.findAll();
List<GatewayResourceProfile> gatewayResourceProfileList = new ArrayList<>();
@@ -151,6 +156,7 @@ public class GwyResourceProfileService {
return gatewayResourceProfileList;
}
+ @Transactional
public boolean removeComputeResourcePreferenceFromGateway(String gatewayId, String preferenceId) {
ComputeResourcePreferencePK computeResourcePreferencePK = new ComputeResourcePreferencePK();
computeResourcePreferencePK.setGatewayId(gatewayId);
@@ -159,6 +165,7 @@ public class GwyResourceProfileService {
return true;
}
+ @Transactional
public boolean removeDataStoragePreferenceFromGateway(String gatewayId, String preferenceId) {
StoragePreferencePK storagePreferencePK = new StoragePreferencePK();
storagePreferencePK.setGatewayId(gatewayId);
@@ -167,10 +174,12 @@ public class GwyResourceProfileService {
return true;
}
+ @Transactional(readOnly = true)
public boolean isGatewayResourceProfileExists(String gatewayId) throws AppCatalogException {
return gwyResourceProfileRepository.existsById(gatewayId);
}
+ @Transactional(readOnly = true)
public ComputeResourcePreference getComputeResourcePreference(String gatewayId, String hostId) {
ComputeResourcePreferencePK computeResourcePreferencePK = new ComputeResourcePreferencePK();
computeResourcePreferencePK.setGatewayId(gatewayId);
@@ -186,6 +195,7 @@ public class GwyResourceProfileService {
return computeResourcePreference;
}
+ @Transactional(readOnly = true)
public StoragePreference getStoragePreference(String gatewayId, String storageId) {
StoragePreferencePK storagePreferencePK = new StoragePreferencePK();
storagePreferencePK.setStorageResourceId(storageId);
@@ -196,6 +206,7 @@ public class GwyResourceProfileService {
.orElse(null);
}
+ @Transactional(readOnly = true)
public List<ComputeResourcePreference> getAllComputeResourcePreferences(String gatewayId) {
List<ComputeResourcePreferenceEntity> entities = computeResourcePrefRepository.findByGatewayId(gatewayId);
List<ComputeResourcePreference> preferences = entities.stream()
@@ -211,6 +222,7 @@ public class GwyResourceProfileService {
return preferences;
}
+ @Transactional(readOnly = true)
public List<StoragePreference> getAllStoragePreferences(String gatewayId) {
List<StoragePreferenceEntity> entities = storagePrefRepository.findByGatewayId(gatewayId);
return entities.stream()
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessErrorService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessErrorService.java
index 8d250bc557..5b52edc488 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessErrorService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessErrorService.java
@@ -20,10 +20,11 @@
package org.apache.airavata.registry.services;
import com.github.dozermapper.core.Mapper;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
import org.apache.airavata.model.commons.ErrorModel;
import org.apache.airavata.registry.entities.expcatalog.ProcessErrorEntity;
+import org.apache.airavata.registry.entities.expcatalog.ProcessErrorPK;
import org.apache.airavata.registry.exceptions.RegistryException;
import org.apache.airavata.registry.repositories.expcatalog.ProcessErrorRepository;
import org.springframework.stereotype.Service;
@@ -31,32 +32,63 @@ import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
-public class ProcessErrorService {
- private final ProcessErrorRepository processErrorRepository;
- private final Mapper mapper;
+public class ProcessErrorService extends BaseErrorService<ProcessErrorEntity, ProcessErrorRepository, ProcessErrorPK> {
public ProcessErrorService(ProcessErrorRepository processErrorRepository, Mapper mapper) {
- this.processErrorRepository = processErrorRepository;
- this.mapper = mapper;
+ super(processErrorRepository, mapper);
}
+ @Override
+ protected BiConsumer<ProcessErrorEntity, String> getParentIdSetter() {
+ return ProcessErrorEntity::setProcessId;
+ }
+
+ @Override
+ protected Function<String, java.util.List<ProcessErrorEntity>> getFindByParentIdFunction() {
+ return repository::findByProcessId;
+ }
+
+ @Override
+ protected Class<ProcessErrorEntity> getEntityClass() {
+ return ProcessErrorEntity.class;
+ }
+
+ @Override
+ protected Function<ProcessErrorEntity, String> getErrorIdExtractor() {
+ return ProcessErrorEntity::getErrorId;
+ }
+
+ /**
+ * Add a process error.
+ *
+ * @param error The error model to persist
+ * @param processId The ID of the process
+ * @return The ID of the saved error entity
+ * @throws RegistryException if the operation fails
+ */
public String addProcessError(ErrorModel error, String processId) throws RegistryException {
- ProcessErrorEntity entity = mapper.map(error, ProcessErrorEntity.class);
- entity.setProcessId(processId);
- ProcessErrorEntity saved = processErrorRepository.save(entity);
- return saved.getErrorId();
+ return addError(error, processId);
}
+ /**
+ * Update a process error.
+ *
+ * @param error The error model with updated information
+ * @param processId The ID of the process
+ * @throws RegistryException if the operation fails
+ */
public void updateProcessError(ErrorModel error, String processId) throws RegistryException {
- ProcessErrorEntity entity = mapper.map(error, ProcessErrorEntity.class);
- entity.setProcessId(processId);
- processErrorRepository.save(entity);
+ updateError(error, processId);
}
- public List<ErrorModel> getProcessError(String processId) throws RegistryException {
- List<ProcessErrorEntity> entities = processErrorRepository.findByProcessId(processId);
- List<ErrorModel> result = new ArrayList<>();
- entities.forEach(e -> result.add(mapper.map(e, ErrorModel.class)));
- return result;
+ /**
+ * Retrieve all errors for a process.
+ *
+ * @param processId The ID of the process
+ * @return List of error models
+ * @throws RegistryException if the operation fails
+ */
+ public java.util.List<ErrorModel> getProcessError(String processId) throws RegistryException {
+ return getErrors(processId);
}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessService.java
index cb7d5ac389..04dfee119c 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/ProcessService.java
@@ -41,7 +41,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@Transactional
public class ProcessService {
private static final Logger logger = LoggerFactory.getLogger(ProcessService.class);
@@ -97,6 +96,7 @@ public class ProcessService {
}
}
+ @Transactional
public String addProcess(ProcessModel process, String experimentId) throws RegistryException {
process.setExperimentId(experimentId);
@@ -106,16 +106,19 @@ public class ProcessService {
return processId;
}
+ @Transactional
public void updateProcess(ProcessModel updatedProcess, String processId) throws RegistryException {
saveProcessModelData(updatedProcess);
}
+ @Transactional(readOnly = true)
public ProcessModel getProcess(String processId) throws RegistryException {
ProcessEntity entity = processRepository.findById(processId).orElse(null);
if (entity == null) return null;
return mapper.map(entity, ProcessModel.class);
}
+ @Transactional
public String addProcessResourceSchedule(
ComputationalResourceSchedulingModel computationalResourceSchedulingModel, String processId)
throws RegistryException {
@@ -125,17 +128,20 @@ public class ProcessService {
return processId;
}
+ @Transactional
public String updateProcessResourceSchedule(
ComputationalResourceSchedulingModel computationalResourceSchedulingModel, String processId)
throws RegistryException {
return addProcessResourceSchedule(computationalResourceSchedulingModel, processId);
}
+ @Transactional(readOnly = true)
public ComputationalResourceSchedulingModel getProcessResourceSchedule(String processId) throws RegistryException {
ProcessModel processModel = getProcess(processId);
return processModel.getProcessResourceSchedule();
}
+ @Transactional(readOnly = true)
public List<ProcessModel> getProcessList(String fieldName, Object value) throws RegistryException {
List<ProcessModel> processModelList;
@@ -152,6 +158,7 @@ public class ProcessService {
return processModelList;
}
+ @Transactional(readOnly = true)
public List<String> getProcessIds(String fieldName, Object value) throws RegistryException {
List<String> processIds = new ArrayList<>();
List<ProcessModel> processModelList = getProcessList(fieldName, value);
@@ -161,14 +168,17 @@ public class ProcessService {
return processIds;
}
+ @Transactional(readOnly = true)
public boolean isProcessExist(String processId) throws RegistryException {
return processRepository.existsById(processId);
}
+ @Transactional
public void removeProcess(String processId) throws RegistryException {
processRepository.deleteById(processId);
}
+ @Transactional(readOnly = true)
public List<ProcessModel> getAllProcesses(int offset, int limit) {
List<ProcessEntity> entities = processRepository.findAll();
List<ProcessModel> result = new ArrayList<>();
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/TaskErrorService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/TaskErrorService.java
index cfa46e54d8..59530b00a9 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/TaskErrorService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/TaskErrorService.java
@@ -20,10 +20,11 @@
package org.apache.airavata.registry.services;
import com.github.dozermapper.core.Mapper;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
import org.apache.airavata.model.commons.ErrorModel;
import org.apache.airavata.registry.entities.expcatalog.TaskErrorEntity;
+import org.apache.airavata.registry.entities.expcatalog.TaskErrorPK;
import org.apache.airavata.registry.exceptions.RegistryException;
import org.apache.airavata.registry.repositories.expcatalog.TaskErrorRepository;
import org.springframework.stereotype.Service;
@@ -31,32 +32,63 @@ import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
-public class TaskErrorService {
- private final TaskErrorRepository taskErrorRepository;
- private final Mapper mapper;
+public class TaskErrorService extends BaseErrorService<TaskErrorEntity, TaskErrorRepository, TaskErrorPK> {
public TaskErrorService(TaskErrorRepository taskErrorRepository, Mapper mapper) {
- this.taskErrorRepository = taskErrorRepository;
- this.mapper = mapper;
+ super(taskErrorRepository, mapper);
}
+ @Override
+ protected BiConsumer<TaskErrorEntity, String> getParentIdSetter() {
+ return TaskErrorEntity::setTaskId;
+ }
+
+ @Override
+ protected Function<String, java.util.List<TaskErrorEntity>> getFindByParentIdFunction() {
+ return repository::findByTaskId;
+ }
+
+ @Override
+ protected Class<TaskErrorEntity> getEntityClass() {
+ return TaskErrorEntity.class;
+ }
+
+ @Override
+ protected Function<TaskErrorEntity, String> getErrorIdExtractor() {
+ return TaskErrorEntity::getErrorId;
+ }
+
+ /**
+ * Add a task error.
+ *
+ * @param error The error model to persist
+ * @param taskId The ID of the task
+ * @return The ID of the saved error entity
+ * @throws RegistryException if the operation fails
+ */
public String addTaskError(ErrorModel error, String taskId) throws RegistryException {
- TaskErrorEntity entity = mapper.map(error, TaskErrorEntity.class);
- entity.setTaskId(taskId);
- TaskErrorEntity saved = taskErrorRepository.save(entity);
- return saved.getErrorId();
+ return addError(error, taskId);
}
+ /**
+ * Update a task error.
+ *
+ * @param error The error model with updated information
+ * @param taskId The ID of the task
+ * @throws RegistryException if the operation fails
+ */
public void updateTaskError(ErrorModel error, String taskId) throws RegistryException {
- TaskErrorEntity entity = mapper.map(error, TaskErrorEntity.class);
- entity.setTaskId(taskId);
- taskErrorRepository.save(entity);
+ updateError(error, taskId);
}
- public List<ErrorModel> getTaskError(String taskId) throws RegistryException {
- List<TaskErrorEntity> entities = taskErrorRepository.findByTaskId(taskId);
- List<ErrorModel> result = new ArrayList<>();
- entities.forEach(e -> result.add(mapper.map(e, ErrorModel.class)));
- return result;
+ /**
+ * Retrieve all errors for a task.
+ *
+ * @param taskId The ID of the task
+ * @return List of error models
+ * @throws RegistryException if the operation fails
+ */
+ public java.util.List<ErrorModel> getTaskError(String taskId) throws RegistryException {
+ return getErrors(taskId);
}
}
diff --git a/airavata-api/src/main/java/org/apache/airavata/registry/services/UserResourceProfileService.java b/airavata-api/src/main/java/org/apache/airavata/registry/services/UserResourceProfileService.java
index d4478675cd..ab19df294f 100644
--- a/airavata-api/src/main/java/org/apache/airavata/registry/services/UserResourceProfileService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/registry/services/UserResourceProfileService.java
@@ -42,7 +42,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
-@Transactional
public class UserResourceProfileService {
private static final Logger logger = LoggerFactory.getLogger(UserResourceProfileService.class);
@@ -62,10 +61,12 @@ public class UserResourceProfileService {
this.mapper = mapper;
}
+ @Transactional
public String addUserResourceProfile(UserResourceProfile userResourceProfile) throws AppCatalogException {
return saveUserResourceProfileData(userResourceProfile);
}
+ @Transactional
public void updateUserResourceProfile(String userId, String gatewayId, UserResourceProfile updatedProfile)
throws AppCatalogException {
saveUserResourceProfileData(updatedProfile);
@@ -111,6 +112,7 @@ public class UserResourceProfileService {
return userResourceProfileRepository.save(userResourceProfileEntity);
}
+ @Transactional(readOnly = true)
public UserResourceProfile getUserResourceProfile(String userId, String gatewayId) throws AppCatalogException {
UserResourceProfilePK userResourceProfilePK = new UserResourceProfilePK();
userResourceProfilePK.setUserId(userId);
@@ -121,6 +123,7 @@ public class UserResourceProfileService {
return mapper.map(entity, UserResourceProfile.class);
}
+ @Transactional(readOnly = true)
public UserComputeResourcePreference getUserComputeResourcePreference(
String userId, String gatewayId, String hostId) throws AppCatalogException {
UserComputeResourcePreferencePK userComputeResourcePreferencePK = new UserComputeResourcePreferencePK();
@@ -133,6 +136,7 @@ public class UserResourceProfileService {
.orElse(null);
}
+ @Transactional(readOnly = true)
public UserStoragePreference getUserStoragePreference(String userId, String gatewayId, String storageId)
throws AppCatalogException {
UserStoragePreferencePK userStoragePreferencePK = new UserStoragePreferencePK();
@@ -145,6 +149,7 @@ public class UserResourceProfileService {
.orElse(null);
}
+ @Transactional(readOnly = true)
public List<UserResourceProfile> getAllUserResourceProfiles() throws AppCatalogException {
List<UserResourceProfileEntity> entities = userResourceProfileRepository.findAll();
List<UserResourceProfile> result = new ArrayList<>();
@@ -152,6 +157,7 @@ public class UserResourceProfileService {
return result;
}
+ @Transactional(readOnly = true)
public List<UserComputeResourcePreference> getAllUserComputeResourcePreferences(String userId, String gatewayId)
throws AppCatalogException {
List<UserComputeResourcePreferenceEntity> entities =
@@ -161,6 +167,7 @@ public class UserResourceProfileService {
.collect(java.util.stream.Collectors.toList());
}
+ @Transactional(readOnly = true)
public List<UserStoragePreference> getAllUserStoragePreferences(String userId, String gatewayId)
throws AppCatalogException {
List<UserStoragePreferenceEntity> entities =
@@ -170,6 +177,7 @@ public class UserResourceProfileService {
.collect(java.util.stream.Collectors.toList());
}
+ @Transactional(readOnly = true)
public List<String> getGatewayProfileIds(String gatewayName) throws AppCatalogException {
List<UserResourceProfileEntity> entities = userResourceProfileRepository.findAll();
List<String> gatewayIdList = new ArrayList<>();
@@ -182,10 +190,12 @@ public class UserResourceProfileService {
return gatewayIdList;
}
+ @Transactional(readOnly = true)
public String getUserNamefromID(String userId, String gatewayID) throws AppCatalogException {
return userId;
}
+ @Transactional
public boolean removeUserResourceProfile(String userId, String gatewayId) throws AppCatalogException {
UserResourceProfilePK userResourceProfilePK = new UserResourceProfilePK();
userResourceProfilePK.setUserId(userId);
@@ -197,6 +207,7 @@ public class UserResourceProfileService {
return true;
}
+ @Transactional
public boolean removeUserComputeResourcePreferenceFromGateway(String userId, String gatewayId, String preferenceId)
throws AppCatalogException {
UserComputeResourcePreferencePK userComputeResourcePreferencePK = new UserComputeResourcePreferencePK();
@@ -207,6 +218,7 @@ public class UserResourceProfileService {
return true;
}
+ @Transactional
public boolean removeUserDataStoragePreferenceFromGateway(String userId, String gatewayId, String preferenceId)
throws AppCatalogException {
UserStoragePreferencePK userStoragePreferencePK = new UserStoragePreferencePK();
@@ -217,6 +229,7 @@ public class UserResourceProfileService {
return true;
}
+ @Transactional(readOnly = true)
public boolean isUserResourceProfileExists(String userId, String gatewayId) throws AppCatalogException {
UserResourceProfilePK userResourceProfilePK = new UserResourceProfilePK();
userResourceProfilePK.setUserId(userId);
@@ -224,6 +237,7 @@ public class UserResourceProfileService {
return userResourceProfileRepository.existsById(userResourceProfilePK);
}
+ @Transactional(readOnly = true)
public boolean isUserComputeResourcePreferenceExists(String userId, String gatewayId, String preferenceId)
throws AppCatalogException {
UserComputeResourcePreferencePK userComputeResourcePreferencePK = new UserComputeResourcePreferencePK();
diff --git a/airavata-api/src/main/java/org/apache/airavata/service/AiravataService.java b/airavata-api/src/main/java/org/apache/airavata/service/AiravataService.java
index 665d969b4e..bde814372c 100644
--- a/airavata-api/src/main/java/org/apache/airavata/service/AiravataService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/service/AiravataService.java
@@ -151,21 +151,42 @@ public class AiravataService {
private record SharingEntity(Entity delegate) {}
private boolean validateString(String name) {
- boolean valid = true;
- if (name == null || name.equals("") || name.trim().length() == 0) {
- valid = false;
- }
- return valid;
+ return name != null && !name.trim().isEmpty();
}
private AiravataSystemException airavataSystemException(
AiravataErrorType errorType, String message, Throwable cause) {
- var exception = new AiravataSystemException(errorType);
- exception.setMessage(message);
- if (cause != null) {
- exception.initCause(cause);
+ return org.apache.airavata.common.exception.ExceptionHandlerUtil.wrapAsAiravataException(
+ errorType, message, cause);
+ }
+
+ /**
+ * Functional interface for operations that may throw RegistryServiceException.
+ */
+ @FunctionalInterface
+ private interface RegistryOperation<T> {
+ T execute() throws RegistryServiceException;
+ }
+
+ /**
+ * Helper method to execute registry operations with standardized error handling.
+ * Reduces boilerplate code for try-catch blocks.
+ *
+ * @param operation The operation name for logging
+ * @param registryOp The operation to execute
+ * @param <T> The return type
+ * @return The result of the operation
+ * @throws AiravataSystemException if the operation fails
+ */
+ private <T> T executeRegistryOperation(String operation, RegistryOperation<T> registryOp)
+ throws AiravataSystemException {
+ try {
+ return registryOp.execute();
+ } catch (RegistryServiceException e) {
+ String msg = String.format("Error while %s: %s", operation, e.getMessage());
+ logger.error(msg, e);
+ throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
}
- return exception;
}
private boolean safeIsUserResourceProfileExists(AuthzToken authzToken, String userId, String gatewayId)
@@ -1171,109 +1192,59 @@ public class AiravataService {
}
public ComputeResourceDescription getComputeResource(String computeResourceId) throws AiravataSystemException {
- try {
- return registryService.getComputeResource(computeResourceId);
- } catch (RegistryServiceException e) {
- String msg = "Error while retrieving compute resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("retrieving compute resource",
+ () -> registryService.getComputeResource(computeResourceId));
}
public String registerComputeResource(ComputeResourceDescription computeResourceDescription)
throws AiravataSystemException {
- try {
- return registryService.registerComputeResource(computeResourceDescription);
- } catch (RegistryServiceException e) {
- String msg = "Error while saving compute resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("saving compute resource",
+ () -> registryService.registerComputeResource(computeResourceDescription));
}
public boolean updateComputeResource(
String computeResourceId, ComputeResourceDescription computeResourceDescription)
throws AiravataSystemException {
- try {
- return registryService.updateComputeResource(computeResourceId, computeResourceDescription);
- } catch (RegistryServiceException e) {
- String msg = "Error while updating compute resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("updating compute resource",
+ () -> registryService.updateComputeResource(computeResourceId, computeResourceDescription));
}
public boolean deleteComputeResource(String computeResourceId) throws AiravataSystemException {
- try {
- return registryService.deleteComputeResource(computeResourceId);
- } catch (RegistryServiceException e) {
- String msg = "Error while deleting compute resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("deleting compute resource",
+ () -> registryService.deleteComputeResource(computeResourceId));
}
public Map<String, String> getAllComputeResourceNames() throws AiravataSystemException {
- try {
- return registryService.getAllComputeResourceNames();
- } catch (RegistryServiceException e) {
- String msg = "Error while retrieving compute resource names: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("retrieving compute resource names",
+ () -> registryService.getAllComputeResourceNames());
}
public String registerStorageResource(StorageResourceDescription storageResourceDescription)
throws AiravataSystemException {
- try {
- return registryService.registerStorageResource(storageResourceDescription);
- } catch (RegistryServiceException e) {
- String msg = "Error while saving storage resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("saving storage resource",
+ () -> registryService.registerStorageResource(storageResourceDescription));
}
public StorageResourceDescription getStorageResource(String storageResourceId) throws AiravataSystemException {
- try {
- return registryService.getStorageResource(storageResourceId);
- } catch (RegistryServiceException e) {
- String msg = "Error while retrieving storage resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("retrieving storage resource",
+ () -> registryService.getStorageResource(storageResourceId));
}
public boolean updateStorageResource(
String storageResourceId, StorageResourceDescription storageResourceDescription)
throws AiravataSystemException {
- try {
- return registryService.updateStorageResource(storageResourceId, storageResourceDescription);
- } catch (RegistryServiceException e) {
- String msg = "Error while updating storage resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("updating storage resource",
+ () -> registryService.updateStorageResource(storageResourceId, storageResourceDescription));
}
public boolean deleteStorageResource(String storageResourceId) throws AiravataSystemException {
- try {
- return registryService.deleteStorageResource(storageResourceId);
- } catch (RegistryServiceException e) {
- String msg = "Error while deleting storage resource: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("deleting storage resource",
+ () -> registryService.deleteStorageResource(storageResourceId));
}
public Map<String, String> getAllStorageResourceNames() throws AiravataSystemException {
- try {
- return registryService.getAllStorageResourceNames();
- } catch (RegistryServiceException e) {
- String msg = "Error while retrieving storage resource names: " + e.getMessage();
- logger.error(msg, e);
- throw airavataSystemException(AiravataErrorType.INTERNAL_ERROR, msg, e);
- }
+ return executeRegistryOperation("retrieving storage resource names",
+ () -> registryService.getAllStorageResourceNames());
}
public String registerGatewayResourceProfile(GatewayResourceProfile gatewayResourceProfile)
diff --git a/airavata-api/src/main/java/org/apache/airavata/service/OrchestratorService.java b/airavata-api/src/main/java/org/apache/airavata/service/OrchestratorService.java
index 4d2da5d1f0..691ce21af9 100644
--- a/airavata-api/src/main/java/org/apache/airavata/service/OrchestratorService.java
+++ b/airavata-api/src/main/java/org/apache/airavata/service/OrchestratorService.java
@@ -27,7 +27,7 @@ import java.util.concurrent.ExecutorService;
import org.apache.airavata.api.thrift.util.ThriftUtils;
import org.apache.airavata.common.exception.AiravataException;
import org.apache.airavata.common.logging.MDCConstants;
-import org.apache.airavata.common.logging.MDCUtil;
+import org.apache.airavata.common.logging.LoggingUtil;
import org.apache.airavata.common.utils.AiravataUtils;
import org.apache.airavata.common.utils.ZkConstants;
import org.apache.airavata.config.AiravataServerProperties;
@@ -894,7 +894,7 @@ public class OrchestratorService {
logger.error("expId: " + experimentId + ", Error while launching single app experiment", e);
}
};
- executorService.execute(MDCUtil.wrapWithMDC(runner));
+ executorService.execute(LoggingUtil.withMDC(runner));
}
}
return result;
diff --git a/airavata-api/src/main/java/org/apache/airavata/sharing/messaging/SharingServiceDBEventHandler.java b/airavata-api/src/main/java/org/apache/airavata/sharing/messaging/SharingServiceDBEventHandler.java
index eedb937839..262d1dbd62 100644
--- a/airavata-api/src/main/java/org/apache/airavata/sharing/messaging/SharingServiceDBEventHandler.java
+++ b/airavata-api/src/main/java/org/apache/airavata/sharing/messaging/SharingServiceDBEventHandler.java
@@ -108,7 +108,8 @@ public class SharingServiceDBEventHandler implements MessageHandler {
break;
case READ:
- // FIXME: Remove if not required
+ // FIXME: Remove if not required - READ permission handling may be redundant
+ // Verify if this case is needed after reviewing permission model
break;
case DELETE:
diff --git a/airavata-api/src/main/java/org/apache/airavata/sharing/repositories/AbstractRepository.java b/airavata-api/src/main/java/org/apache/airavata/sharing/repositories/AbstractRepository.java
index 9ba6d5568b..22ae695eff 100644
--- a/airavata-api/src/main/java/org/apache/airavata/sharing/repositories/AbstractRepository.java
+++ b/airavata-api/src/main/java/org/apache/airavata/sharing/repositories/AbstractRepository.java
@@ -64,10 +64,40 @@ public abstract class AbstractRepository<T, E, Id> {
return update(t);
}
- // FIXME do a bulk insert
+ /**
+ * Bulk create entities. Uses batch processing for better performance.
+ *
+ * @param tList List of Thrift models to persist
+ * @return List of persisted Thrift models
+ * @throws SharingRegistryException if the operation fails
+ */
@Transactional
public List<T> create(List<T> tList) throws SharingRegistryException {
- return update(tList);
+ if (tList == null || tList.isEmpty()) {
+ return new ArrayList<>();
+ }
+ EntityManager em = getEntityManager();
+ List<T> result = new ArrayList<>();
+ int batchSize = 50; // Process in batches to avoid memory issues
+
+ for (int i = 0; i < tList.size(); i++) {
+ E entity = getMapper().map(tList.get(i), dbEntityGenericClass);
+ em.persist(entity);
+ result.add(getMapper().map(entity, thriftGenericClass));
+
+ // Flush and clear every batchSize entities to manage memory
+ if ((i + 1) % batchSize == 0) {
+ em.flush();
+ em.clear();
+ }
+ }
+
+ // Final flush for remaining entities
+ if (tList.size() % batchSize != 0) {
+ em.flush();
+ }
+
+ return result;
}
@Transactional
@@ -78,12 +108,40 @@ public abstract class AbstractRepository<T, E, Id> {
return getMapper().map(persistedCopy, thriftGenericClass);
}
- // FIXME do a bulk update
+ /**
+ * Bulk update entities. Uses batch processing for better performance.
+ *
+ * @param tList List of Thrift models to update
+ * @return List of updated Thrift models
+ * @throws SharingRegistryException if the operation fails
+ */
@Transactional
public List<T> update(List<T> tList) throws SharingRegistryException {
- List<T> returnList = new ArrayList<>();
- for (T temp : tList) returnList.add(update(temp));
- return returnList;
+ if (tList == null || tList.isEmpty()) {
+ return new ArrayList<>();
+ }
+ EntityManager em = getEntityManager();
+ List<T> result = new ArrayList<>();
+ int batchSize = 50; // Process in batches to avoid memory issues
+
+ for (int i = 0; i < tList.size(); i++) {
+ E entity = getMapper().map(tList.get(i), dbEntityGenericClass);
+ E merged = em.merge(entity);
+ result.add(getMapper().map(merged, thriftGenericClass));
+
+ // Flush and clear every batchSize entities to manage memory
+ if ((i + 1) % batchSize == 0) {
+ em.flush();
+ em.clear();
+ }
+ }
+
+ // Final flush for remaining entities
+ if (tList.size() % batchSize != 0) {
+ em.flush();
+ }
+
+ return result;
}
@Transactional