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
Show file tree
Hide file tree
Changes from all commits
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ Version 2.0. See the file "[LICENSE](LICENSE)" for more information.
Module that provides a facade layer (backed-for-frontend) for FOLIO circulation
applications.

### Environment variables

| Name | Default value | Description |
|:------------------------------|:--------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| JAVA_OPTIONS | -XX:MaxRAMPercentage=66.0 | Java options |
| SYSTEM_USER_USERNAME | mod-circulation-bff | Username for `mod-circulation-bff` system user |
| SYSTEM_USER_PASSWORD | mod-circulation-bff | Password for `mod-circulation-bff` system user |
| SYSTEM_USER_ENABLED | true | Defines if system user must be created at service tenant initialization |
| SECURE_TENANT_ID | - | ID of the secure tenant in a consortia-enabled environment |
| OKAPI_URL | http://okapi:9130 | OKAPI URL used to login system user, required |
| ENV | folio | The logical name of the deployment, must be unique across all environments using the same shared Kafka/Elasticsearch clusters, `a-z (any case)`, `0-9`, `-`, `_` symbols only allowed |

## Further information

### Issue tracker
Expand Down
13 changes: 11 additions & 2 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"provides": [
{
"id": "circulation-bff-ecs-request-external",
"version": "1.1",
"version": "1.2",
"handlers": [
{
"methods": ["POST"],
Expand All @@ -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"
]
}
]
Expand Down Expand Up @@ -254,6 +259,10 @@
"id": "search",
"version": "1.3"
},
{
"id": "consortium-search",
"version": "2.1"
},
{
"id": "user-tenants",
"version": "1.0"
Expand Down
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
Expand Up @@ -3,9 +3,11 @@
import java.util.Collection;

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

public interface SearchService {
SearchInstance findInstanceByItemId(String itemId);
Collection<BffSearchInstance> findInstances(String query);
ConsortiumItem findConsortiumItem(String itemId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public interface SettingsService {
boolean isEcsTlrFeatureEnabled();
boolean isEcsTlrFeatureEnabled(String tenantId);
boolean isEcsTlrFeatureEnabled(boolean isCentralTenant);
}
13 changes: 13 additions & 0 deletions src/main/java/org/folio/circulationbff/service/TenantService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.folio.circulationbff.service;

import java.util.Optional;

public interface TenantService {
String getCurrentTenantId();
Optional<String> getCentralTenantId();
Optional<String> getSecureTenantId();
boolean isCurrentTenantCentral();
boolean isCurrentTenantSecure();
boolean isCentralTenant(String tenantId);
boolean isSecureTenant(String tenantId);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package org.folio.circulationbff.service;

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

public interface UserTenantsService {
String getCurrentTenant();
String getCentralTenant();
boolean isCentralTenant();
boolean isCentralTenant(String tenantId);
UserTenant getFirstUserTenant();
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
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.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.EcsRequestExternalService;
import org.folio.circulationbff.service.UserTenantsService;
import org.folio.circulationbff.service.SearchService;
import org.folio.circulationbff.service.SettingsService;
import org.folio.circulationbff.service.TenantService;
import org.folio.spring.service.SystemUserScopedExecutionService;
import org.springframework.stereotype.Service;

Expand All @@ -21,18 +28,76 @@ 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 TenantService tenantService;

@Override
public Request createEcsRequestExternal(EcsRequestExternal ecsRequestExternal) {
String centralTenantId = userTenantsService.getCentralTenant();
log.info("createEcsRequestExternal:: centralTenantId={}", centralTenantId);
public Request createEcsRequestExternal(EcsRequestExternal request) {
log.info("createEcsRequestExternal:: requesterId={}, itemId={}, instanceId={}",
request::getRequesterId, request::getItemId, request::getInstanceId);

fetchMissingRequestProperties(request);

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

private Request createEcsRequest(EcsRequestExternal ecsRequestExternal) {
log.info("createEcsRequest:: creating ECS request");
return tenantService.isCurrentTenantSecure()
? createMediatedRequest(ecsRequestExternal)
: createExternalEcsTlr(ecsRequestExternal);
}

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

EcsTlr ecsTlr = systemUserScopedExecutionService.executeSystemUserScoped(centralTenantId,
private Request createExternalEcsTlr(EcsRequestExternal ecsRequestExternal) {
log.info("createExternalEcsTlr:: creating ECS TLR");
EcsTlr ecsTlr = systemUserScopedExecutionService.executeSystemUserScoped(
tenantService.getCentralTenantId().orElseThrow(),
() -> 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
Expand Up @@ -30,6 +30,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;
Expand Down Expand Up @@ -83,6 +84,12 @@ public SearchInstance findInstanceByItemId(String itemId) {
return searchResult.getInstances().get(0);
}

@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.folio.circulationbff.client.feign.CirculationClient;
import org.folio.circulationbff.client.feign.EcsTlrClient;
import org.folio.circulationbff.service.SettingsService;
import org.folio.circulationbff.service.UserTenantsService;
import org.folio.circulationbff.service.TenantService;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
Expand All @@ -17,22 +17,23 @@ public class SettingsServiceImpl implements SettingsService {
public static final String ECS_TLR_FEATURE_SETTINGS = "name=ecsTlrFeature";
private final EcsTlrClient ecsTlrClient;
private final CirculationClient circulationClient;
private final UserTenantsService userTenantsService;
private final TenantService tenantService;

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

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

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

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

private boolean isEcsTlrFeatureEnabledInCentralTenant() {
Boolean ecsTlrFeatureEnabled = ecsTlrClient.getTlrSettings().getEcsTlrFeatureEnabled();
log.info("isEcsTlrFeatureEnabled:: {}", ecsTlrFeatureEnabled);
return ecsTlrFeatureEnabled;
}
}
Loading