Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MCBFF-44: Reimplement mod-patron's logic for placing external ECS TLR requests #50

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
MCBFF-44 Create external ECS TLR
OleksandrVidinieiev committed Jan 27, 2025
commit a6e39dbd667c2b4031f5b48a72102a9aed3b1d50
9 changes: 7 additions & 2 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"provides": [
{
"id": "circulation-bff-ecs-request-external",
"version": "1.1",
"version": "1.2",
"handlers": [
{
"methods": ["POST"],
@@ -14,7 +14,12 @@
"tlr.ecs-request-external.post",
"user-tenants.collection.get",
"circulation.requests.item.get",
"circulation.requests.collection.get"
"circulation.requests.collection.get",
"tlr.settings.get",
"circulation.settings.item.get",
"circulation.settings.collection.get",
"consortium-search.items.collection.get",
"consortium-search.items.item.get"
]
}
]
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.folio.circulationbff.client.feign;

import org.folio.circulationbff.domain.dto.ConsortiumItem;
import org.folio.circulationbff.domain.dto.SearchInstances;
import org.folio.spring.config.FeignClientConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "search", url = "search", configuration = FeignClientConfiguration.class)
public interface SearchClient {

@GetMapping("/instances")
SearchInstances findInstances(@RequestParam String query, @RequestParam boolean expandAll);

@GetMapping("/consortium/item/{itemId}")
ConsortiumItem searchItem(@PathVariable("itemId") String itemId);
}
21 changes: 21 additions & 0 deletions src/main/java/org/folio/circulationbff/config/TenantConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.folio.circulationbff.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import jakarta.annotation.PostConstruct;
import lombok.Data;

@Configuration
@Data
@ConfigurationProperties("folio.tenant")
public class TenantConfig {
private String secureTenantId;

@PostConstruct
private void postConstruct() {
if ("${SECURE_TENANT_ID}".equals(secureTenantId)) {
secureTenantId = null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.folio.circulationbff.domain;

public record EcsTenantConfiguration(boolean isConsortiaEnabled, String currentTenantId,
String centralTenantId, String secureTenantId) {

public boolean isCurrentTenantCentral() {
return isConsortiaEnabled && currentTenantId != null && currentTenantId.equals(centralTenantId);
}

public boolean isCurrentTenantSecure() {
return isConsortiaEnabled && currentTenantId != null && currentTenantId.equals(secureTenantId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.folio.circulationbff.service;

import org.folio.circulationbff.domain.EcsTenantConfiguration;

public interface EcsTenantConfigurationService {
EcsTenantConfiguration getTenantConfiguration();
}
Original file line number Diff line number Diff line change
@@ -3,7 +3,9 @@
import java.util.Collection;

import org.folio.circulationbff.domain.dto.BffSearchInstance;
import org.folio.circulationbff.domain.dto.ConsortiumItem;

public interface SearchService {
Collection<BffSearchInstance> findInstances(String query);
ConsortiumItem findConsortiumItem(String itemId);
}
Original file line number Diff line number Diff line change
@@ -3,4 +3,5 @@
public interface SettingsService {
boolean isEcsTlrFeatureEnabled();
boolean isEcsTlrFeatureEnabled(String tenantId);
boolean isEcsTlrFeatureEnabled(boolean isCentralTenant);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package org.folio.circulationbff.service;

import org.folio.circulationbff.domain.dto.UserTenant;

public interface UserTenantsService {
String getCentralTenant();
boolean isCentralTenant();
UserTenant getFirstUserTenant();
boolean isCentralTenant(String tenantId);
boolean isCentralTenant(UserTenant userTenant);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package org.folio.circulationbff.service.impl;

import static org.folio.circulationbff.domain.dto.EcsRequestExternal.RequestLevelEnum.ITEM;
import static org.folio.circulationbff.domain.dto.EcsRequestExternal.RequestLevelEnum.TITLE;

import org.folio.circulationbff.client.feign.CirculationClient;
import org.folio.circulationbff.client.feign.EcsTlrClient;
import org.folio.circulationbff.domain.EcsTenantConfiguration;
import org.folio.circulationbff.domain.dto.ConsortiumItem;
import org.folio.circulationbff.domain.dto.EcsRequestExternal;
import org.folio.circulationbff.domain.dto.EcsRequestExternal.RequestLevelEnum;
import org.folio.circulationbff.domain.dto.EcsTlr;
import org.folio.circulationbff.domain.dto.Request;
import org.folio.circulationbff.service.EcsTenantConfigurationService;
import org.folio.circulationbff.service.EcsRequestExternalService;
import org.folio.circulationbff.service.UserTenantsService;
import org.folio.circulationbff.service.SearchService;
import org.folio.circulationbff.service.SettingsService;
import org.folio.spring.service.SystemUserScopedExecutionService;
import org.springframework.stereotype.Service;

@@ -21,18 +29,79 @@ public class EcsRequestExternalServiceImpl implements EcsRequestExternalService
private final SystemUserScopedExecutionService systemUserScopedExecutionService;
private final EcsTlrClient ecsTlrClient;
private final CirculationClient circulationClient;
private final UserTenantsService userTenantsService;

private final SettingsService settingsService;
private final SearchService searchService;
private final EcsTenantConfigurationService ecsTenantConfigurationService;

@Override
public Request createEcsRequestExternal(EcsRequestExternal ecsRequestExternal) {
String centralTenantId = userTenantsService.getCentralTenant();
log.info("createEcsRequestExternal:: centralTenantId={}", centralTenantId);
public Request createEcsRequestExternal(EcsRequestExternal request) {
log.info("createEcsRequestExternal:: creating external request");
fetchMissingRequestProperties(request);
EcsTenantConfiguration tenantConfiguration = ecsTenantConfigurationService.getTenantConfiguration();

return settingsService.isEcsTlrFeatureEnabled(tenantConfiguration.isCurrentTenantCentral())
? createEcsRequest(request, tenantConfiguration)
: createCirculationRequest(request);
}

private Request createEcsRequest(EcsRequestExternal ecsRequestExternal,
EcsTenantConfiguration tenantConfiguration) {

log.info("createEcsRequest:: creating ECS request");
return tenantConfiguration.isCurrentTenantSecure()
? createMediatedRequest(ecsRequestExternal)
: createExternalEcsTlr(ecsRequestExternal, tenantConfiguration);
}

private Request createCirculationRequest(EcsRequestExternal ecsRequestExternal) {
log.info("createCirculationRequest:: creating circulation request");
return ecsRequestExternal.getRequestLevel() == TITLE
? createTitleLevelRequest(ecsRequestExternal)
: createItemLevelRequest(ecsRequestExternal);
}

private Request createExternalEcsTlr(EcsRequestExternal ecsRequestExternal,
EcsTenantConfiguration tenantConfiguration) {

EcsTlr ecsTlr = systemUserScopedExecutionService.executeSystemUserScoped(centralTenantId,
log.info("createExternalEcsTlr:: creating ECS TLR");
EcsTlr ecsTlr = systemUserScopedExecutionService.executeSystemUserScoped(
tenantConfiguration.centralTenantId(),
() -> ecsTlrClient.createEcsExternalRequest(ecsRequestExternal));
log.info("createEcsRequestExternal:: ecsTlr: {}", ecsTlr);
log.info("createExternalEcsTlr:: ECS TLR created: {}", ecsTlr::getId);
log.debug("createExternalEcsTlr:: ecsTlr: {}", ecsTlr);

log.info("createExternalEcsTlr:: fetching primary request");
return circulationClient.getRequestById(ecsTlr.getPrimaryRequestId());
}

private Request createMediatedRequest(EcsRequestExternal ecsRequestExternal) {
log.info("createMediatedRequest:: creating mediated request");
// POST /requests-mediated/mediated-requests
return new Request();
}

private Request createItemLevelRequest(EcsRequestExternal ecsRequestExternal) {
log.info("createItemLevelRequest:: creating item level request");
// POST /circulation/requests
return new Request();
}

private Request createTitleLevelRequest(EcsRequestExternal ecsRequestExternal) {
log.info("createTitleLevelRequest:: creating title level request");
// POST /circulation/requests/instances
return new Request();
}

private void fetchMissingRequestProperties(EcsRequestExternal request) {
String itemId = request.getItemId();
RequestLevelEnum requestLevel = request.getRequestLevel();
log.info("fetchMissingRequestProperties:: requestLevel={}, itemId={}", requestLevel, itemId);
if (requestLevel == ITEM && itemId != null) {
log.info("fetchMissingRequestProperties:: fetching item for item level request");
ConsortiumItem item = searchService.findConsortiumItem(itemId);
request.instanceId(item.getInstanceId())
.holdingsRecordId(item.getHoldingsRecordId());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.folio.circulationbff.service.impl;

import org.folio.circulationbff.config.TenantConfig;
import org.folio.circulationbff.domain.EcsTenantConfiguration;
import org.folio.circulationbff.domain.dto.UserTenant;
import org.folio.circulationbff.service.EcsTenantConfigurationService;
import org.folio.circulationbff.service.UserTenantsService;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Service
@RequiredArgsConstructor
@Log4j2
public class EcsTenantConfigurationServiceImpl
implements EcsTenantConfigurationService {

private final UserTenantsService userTenantsService;
private final TenantConfig tenantConfig;

@Override
public EcsTenantConfiguration getTenantConfiguration() {
UserTenant userTenant = userTenantsService.getFirstUserTenant();

EcsTenantConfiguration tenantConfiguration = userTenant == null
? new EcsTenantConfiguration(false, null, null, null)
: new EcsTenantConfiguration(true, userTenant.getTenantId(), userTenant.getCentralTenantId(),
tenantConfig.getSecureTenantId());

log.info("getTenantConfiguration:: {}", tenantConfiguration);
return tenantConfiguration;
}
}
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
import org.folio.circulationbff.domain.dto.BffSearchItemLocation;
import org.folio.circulationbff.domain.dto.BffSearchItemMaterialType;
import org.folio.circulationbff.domain.dto.BffSearchItemStatus;
import org.folio.circulationbff.domain.dto.ConsortiumItem;
import org.folio.circulationbff.domain.dto.Contributor;
import org.folio.circulationbff.domain.dto.HoldingsRecord;
import org.folio.circulationbff.domain.dto.HoldingsRecords;
@@ -71,6 +72,12 @@ public class SearchServiceImpl implements SearchService {
private final BulkFetchingService fetchingService;
private final SearchInstanceMapper searchInstanceMapper;

@Override
public ConsortiumItem findConsortiumItem(String itemId) {
log.info("findConsortiumItem:: looking for item {}", itemId);
return searchClient.searchItem(itemId);
}

@Override
public Collection<BffSearchInstance> findInstances(String query) {
log.info("findInstances:: searching instances by query: {}", query);
Original file line number Diff line number Diff line change
@@ -21,18 +21,19 @@ public class SettingsServiceImpl implements SettingsService {

@Override
public boolean isEcsTlrFeatureEnabled() {
if (userTenantsService.isCentralTenant()) {
return ecsTlrClient.getTlrSettings().getEcsTlrFeatureEnabled();
}
return isTlrEnabledInCirculationSettings();
return isEcsTlrFeatureEnabled(userTenantsService.isCentralTenant());
}

@Override
public boolean isEcsTlrFeatureEnabled(String tenantId) {
if (userTenantsService.isCentralTenant(tenantId)) {
return ecsTlrClient.getTlrSettings().getEcsTlrFeatureEnabled();
}
return isTlrEnabledInCirculationSettings();
return isEcsTlrFeatureEnabled(userTenantsService.isCentralTenant(tenantId));
}

@Override
public boolean isEcsTlrFeatureEnabled(boolean isCentralTenant) {
return isCentralTenant
? isEcsTlrFeatureEnabledInCentralTenant()
: isTlrEnabledInCirculationSettings();
}

private boolean isTlrEnabledInCirculationSettings() {
@@ -50,4 +51,10 @@ private boolean isTlrEnabledInCirculationSettings() {
}
return false;
}

private boolean isEcsTlrFeatureEnabledInCentralTenant() {
Boolean ecsTlrFeatureEnabled = ecsTlrClient.getTlrSettings().getEcsTlrFeatureEnabled();
log.info("isEcsTlrFeatureEnabled:: {}", ecsTlrFeatureEnabled);
return ecsTlrFeatureEnabled;
}
}
Original file line number Diff line number Diff line change
@@ -32,20 +32,11 @@ public String getCentralTenant() {

@Override
public boolean isCentralTenant() {
UserTenant firstUserTenant = getFirstUserTenant();
if (firstUserTenant == null) {
log.info("isCentralTenant:: failed to fetch user tenants");
return false;
}
String centralTenantId = firstUserTenant.getCentralTenantId();
String tenantId = firstUserTenant.getTenantId();
log.info("isCentralTenant:: centralTenantId={}, tenantId={}", centralTenantId,
tenantId);

return centralTenantId.equals(tenantId);
return isCentralTenant(getFirstUserTenant());
}

private UserTenant getFirstUserTenant() {
@Override
public UserTenant getFirstUserTenant() {
UserTenant firstUserTenant = findFirstUserTenant();
if (firstUserTenant == null) {
log.info("processUserGroupEvent: Failed to get user-tenants info");
@@ -67,20 +58,34 @@ public boolean isCentralTenant(String tenantId) {
return false;
}

@Override
public boolean isCentralTenant(UserTenant userTenant) {
if (userTenant == null) {
log.info("isCentralTenant:: failed to fetch user tenants");
return false;
}
String centralTenantId = userTenant.getCentralTenantId();
String tenantId = userTenant.getTenantId();
log.info("isCentralTenant:: centralTenantId={}, tenantId={}", centralTenantId,
tenantId);

return centralTenantId.equals(tenantId);
}

private UserTenant findFirstUserTenant() {
log.info("findFirstUserTenant:: finding first userTenant");
UserTenant firstUserTenant = null;
UserTenantCollection userTenantCollection = userTenantsClient.getUserTenants(1);
log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
log.debug("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
if (userTenantCollection != null) {
log.info("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
log.debug("findFirstUserTenant:: userTenantCollection: {}", () -> userTenantCollection);
List<UserTenant> userTenants = userTenantCollection.getUserTenants();
if (!userTenants.isEmpty()) {
firstUserTenant = userTenants.get(0);
log.info("findFirstUserTenant:: found userTenant: {}", firstUserTenant);
log.debug("findFirstUserTenant:: found userTenant: {}", firstUserTenant);
}
}
log.info("findFirstUserTenant:: result: {}", firstUserTenant);
log.debug("findFirstUserTenant:: result: {}", firstUserTenant);
return firstUserTenant;
}
}
1 change: 1 addition & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ spring:
enabled: true
folio:
tenant:
secure-tenant-id: ${SECURE_TENANT_ID}
validation:
enabled: true
environment: ${ENV:folio}
2 changes: 2 additions & 0 deletions src/main/resources/swagger.api/circulation-bff.yaml
Original file line number Diff line number Diff line change
@@ -52,3 +52,5 @@ components:
$ref: 'schemas/dto/request/BffRequest.yaml#/BffRequest'
ecs-tlr:
$ref: 'schemas/dto/ecs-tlr/EcsTlr.yaml#/EcsTlr'
consortium-item:
$ref: 'schemas/dto/search/consortiumItem.yaml'
Loading