Skip to content

feat: extract transport-agnostic service layer from Thrift handlers#594

Merged
yasithdev merged 39 commits intomasterfrom
feat/airavata-service-layer
Mar 26, 2026
Merged

feat: extract transport-agnostic service layer from Thrift handlers#594
yasithdev merged 39 commits intomasterfrom
feat/airavata-service-layer

Conversation

@yasithdev
Copy link
Copy Markdown
Contributor

Summary

Extracts all business logic from AiravataServerHandler into a transport-agnostic service layer (org.apache.airavata.service.*), enabling future REST/gRPC transports without duplicating logic.

  • 14 service classes covering all domains (experiments, projects, gateways, credentials, app catalog, resources, sharing, profiles, parsers, SSH accounts, data products, notifications)
  • ThriftAdapter utility eliminates boilerplate try/catch and RequestContext construction — handler methods are one-liner delegates
  • SharingHelper consolidates duplicated sharing utilities across services
  • RequestContext provides transport-agnostic identity (userId, gatewayId, claims)
  • EventPublisher wraps RabbitMQ messaging with typed methods
  • 136 unit tests across 15 test files (Mockito-based, all passing)
  • Integration test infrastructure: AbstractIntegrationTest base with Testcontainers MariaDB, surefire tag filtering (@Tag("integration"))
  • Handler reduced 55%: 6,853 → 3,114 lines; 190 methods delegate through ThriftAdapter
  • Constructor side effects (initSharingRegistry, postInitDefaultGateway) extracted to initialize() method
  • Dockerfile updated: removed obsolete per-service ports (all Thrift multiplexed on 8930)
  • Spotless formatting applied

Architecture

Thrift Handler (thin adapter)
  └─ ThriftAdapter.execute(authzToken, gatewayId, ctx -> service.method(ctx, args))
       └─ RequestContext (transport-agnostic identity)
            └─ Service Layer (business logic, sharing checks, event publishing)
                 └─ RegistryServerHandler / SharingRegistryServerHandler (persistence)

Test plan

  • All 136 service-layer unit tests pass (mvn test -DexcludedGroups=integration)
  • mvn compile succeeds for full project
  • Server boots from clean state with docker compose up -d + mvn exec:java (verified: DB init, RabbitMQ, ZooKeeper all connect)
  • Thrift interface unchanged — existing clients see no difference
  • Integration tests with mvn test -Dgroups=integration -DexcludedGroups="" (requires Docker)

🤖 Generated with Claude Code

Extracts experiment business logic from AiravataServerHandler into a
clean service class with explicit dependency injection. Uses isSharingEnabled()
helper to safely default to false when the setting is absent.
Extract gateway and notification business logic from AiravataServerHandler
into GatewayService and NotificationService with full Mockito test coverage.
…layer

Replace inline gateway and notification method bodies in AiravataServerHandler
with ThriftAdapter one-liners delegating to GatewayService and NotificationService.
Extract credential business logic from AiravataServerHandler into
CredentialService, using RequestContext instead of AuthzToken claims
and direct sharingHandler.userHasAccess() for permission checks.
Replace all 6 credential method bodies in AiravataServerHandler with
ThriftAdapter one-liners delegating to CredentialService.
Extracts createProject, updateProject, deleteProject, getProject,
getUserProjects, and searchProjects business logic from AiravataServerHandler
into a dedicated ProjectService following the established service layer pattern.
Replace the inline business logic in all 6 project methods
(createProject, updateProject, deleteProject, getProject,
getUserProjects, searchProjects) with ThriftAdapter one-liners
delegating to ProjectService.
…ata movement

Extracts all resource-related registry delegates into ResourceService covering compute resources, storage resources, job submission interfaces (LOCAL, SSH, SSHFork, Cloud, UNICORE), data movement interfaces (LOCAL, SCP, UNICORE, GridFTP), resource job managers, and batch queues. Includes 16 unit tests covering each sub-domain.
Replace all compute resource, storage resource, job submission, data movement, resource job manager, and batch queue method bodies in AiravataServerHandler with ThriftAdapter one-liners delegating to ResourceService.
Extracts application module, deployment, and interface logic from
AiravataServerHandler into a dedicated service layer class, including
sharing/permission logic for deployments. Adds 15 unit tests covering
all three sub-domains.
Adds getExperimentStatistics, getExperimentsInProject, getUserExperiments,
getDetailedExperimentTree, updateExperiment, updateExperimentConfiguration,
updateResourceScheduleing, validateExperiment, getJobStatuses, getJobDetails.
Rewires corresponding AiravataServerHandler methods to ThriftAdapter one-liners.
Extracts all gateway resource profile operations (CRUD, compute/storage
preferences, SSH account provisioners) from AiravataServerHandler into
GatewayResourceProfileService. Rewires handler methods to ThriftAdapter
one-liners.
Extracts all user resource profile operations (CRUD, compute/storage
preferences, queue statuses) from AiravataServerHandler into
UserResourceProfileService. Rewires handler methods to ThriftAdapter
one-liners.
…ervice layer

Rewires all remaining experiment methods (getExperimentStatistics, getExperimentsInProject,
getUserExperiments, getDetailedExperimentTree, updateExperiment, updateExperimentConfiguration,
updateResourceScheduleing, validateExperiment, getJobStatuses, getJobDetails) and all gateway
and user resource profile methods in AiravataServerHandler to ThriftAdapter one-liners
delegating to the new service classes.
Extracts registerDataProduct, getDataProduct, registerReplicaLocation,
getParentDataProduct, and getChildDataProducts into DataProductService.
Rewires AiravataServerHandler to delegate via ThriftAdapter.
Extracts shareResourceWithUsers, shareResourceWithGroups, revoke* variants,
getAllAccessible*/getAllDirectlyAccessible* methods, and userHasAccess into
ResourceSharingService. Rewires AiravataServerHandler to delegate via ThriftAdapter.
Extracts createGroupResourceProfile (with sharing rollback), updateGroupResourceProfile,
getGroupResourceProfile, removeGroupResourceProfile, getGroupResourceList, removeGroupCompute*,
getGroupCompute*/getBatchQueue*, and getGatewayGroups into GroupResourceProfileService.
Includes credential validation and sharing entity management.
Rewires AiravataServerHandler to delegate via ThriftAdapter.
Extracts getParser, saveParser, listAllParsers, removeParser, getParsingTemplate,
getParsingTemplatesForExperiment, saveParsingTemplate, removeParsingTemplate, and
listAllParsingTemplates into ParserService.
Rewires AiravataServerHandler to delegate via ThriftAdapter.
- Add isUserExists to GatewayService
- Add fetchIntermediateOutputs, getIntermediateOutputProcessStatus, and launchExperiment to ExperimentService
- Add tests for new methods in ExperimentServiceTest and GatewayServiceTest
…elete orphaned helpers

- isUserExists, fetchIntermediateOutputs, getIntermediateOutputProcessStatus, and launchExperiment now delegate to service layer
- Delete orphaned private helpers: validateString, submitExperiment, submitCancelExperiment, submitExperimentIntermediateOutputsEvent, shareEntityWithAdminGatewayGroups, userHasAccessInternal, getResourceType, createManageSharingPermissionTypeIfMissing, retrieveGatewayGroups
- Accept RegistryServerHandler in constructor (backwards-compatible overload kept)
- Implement retrieveGatewayGroups helper using registry
- validateAdminGroupNotRevoked now checks actual GatewayGroups admin group id
- Pass registryHandler from AiravataServerHandler constructor
Consolidate duplicated isSharingEnabled(), userHasAccess(),
retrieveGatewayGroups(), shareEntityWithAdminGatewayGroups(), and
createManageSharingPermissionTypeIfMissing() from ExperimentService,
ProjectService, CredentialService, ApplicationCatalogService,
GatewayService, GroupResourceProfileService, and ResourceSharingService
into a single SharingHelper utility class.
…tAdapter

ServiceNotFoundException was incorrectly mapped to ExperimentNotFoundException,
which is semantically wrong for non-experiment resources. Map to
AiravataSystemException with a "not found" prefix message instead, since
there is no generic Thrift not-found exception type.
Move initSharingRegistry() and postInitDefaultGateway() calls out of the
constructor into a new public initialize() method. The constructor now only
wires dependencies, while initialization side effects are deferred to
initialize(), which is called explicitly by AiravataServer after construction.
…rvice

Migrated getResourceStorageInfo, getStorageDirectoryInfo, resolveComputeStorageInfoContext,
and resolveStorageStorageInfoContext from AiravataServerHandler into ResourceService. Handler
methods are now pure ThriftAdapter one-liners. ResourceService gains a GroupResourceProfileService
dependency for the group preference fallback chain.
Extracted doesUserHaveSSHAccount, isSSHSetupCompleteForUserComputeResourcePreference,
and setupUserComputeResourcePreferencesForSSH from AiravataServerHandler into a dedicated
SSHAccountService. Handler methods are now ThriftAdapter one-liners. Includes 6 unit tests
covering all methods and error paths.
Moved group resource profile lookup from AiravataServerHandler.launchExperiment into
ExperimentService.launchExperiment, removing the List<GroupResourceProfile> parameter.
ExperimentService gains an optional GroupResourceProfileService set via setter. Handler
method is now a single ThriftAdapter.executeVoid call.
- AbstractIntegrationTest base class with @tag("integration") and MariaDB container
- SharingServiceIntegrationTest: rewrites monolithic sharing test into 13 ordered tests
- ExperimentRepositoryIntegrationTest: template for repository integration tests
- Surefire configured to exclude integration tests by default (run with -Dgroups=integration)
…orts

- README: document the 14-service architecture and transport-agnostic design
- Dockerfile: remove obsolete per-service ports (all Thrift on 8930)
@yasithdev yasithdev merged commit 49ac3ea into master Mar 26, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant