Skip to content

Commit

Permalink
MODTLR-16: Create shadow requester in lending tenant (#19)
Browse files Browse the repository at this point in the history
* MODTLR-16 Implementation and tests

* MODTLR-16 Fix formatting

* MODTLR-16 Fix formatting

* MODTLR-22 Implementation and tests

* MODTLR-22 Rename central tenant to match our setup on Rancher

* MODTLR-22 Refactoring

* MODTLR-22 Major refactoring after merging changes from MODTLR-18

* MODTLR-22 Logging adjustments

* MODTLR-22 Remove unused exception

* MODTLR-22 Minor fixes

* MODTLR-22 Remove fully qualified class name

* MODTLR-22 Add pickupServicePointId to primary request

* MODTLR-22 Remove primary request creation
  • Loading branch information
OleksandrVidinieiev authored Mar 1, 2024
1 parent 180d8d8 commit f773328
Show file tree
Hide file tree
Showing 23 changed files with 817 additions and 130 deletions.
5 changes: 4 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
"permissionsRequired": ["tlr.ecs-tlr.post"],
"modulePermissions": [
"circulation.requests.instances.item.post",
"search.instances.collection.get"
"search.instances.collection.get",
"users.item.get",
"users.collection.get",
"users.item.post"
]
},
{
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/org/folio/client/feign/CirculationClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient(name = "circulation", url = "${folio.okapi-url}", configuration = FeignClientConfiguration.class)
@FeignClient(name = "circulation", url = "circulation", configuration = FeignClientConfiguration.class)
public interface CirculationClient {

@PostMapping("/circulation/requests/instances")
@PostMapping("/requests/instances")
Request createInstanceRequest(Request request);

}
2 changes: 1 addition & 1 deletion src/main/java/org/folio/client/feign/SearchClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

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

@GetMapping("/instances")
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/folio/client/feign/UsersClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.folio.client.feign;

import org.folio.domain.dto.User;
import org.folio.spring.config.FeignClientConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

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

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
User postUser(@RequestBody User user);

@GetMapping("/{userId}")
User getUser(@PathVariable String userId);
}
6 changes: 6 additions & 0 deletions src/main/java/org/folio/domain/RequestWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.folio.domain;

import org.folio.domain.dto.Request;

public record RequestWrapper(Request request, String tenantId) {
}
12 changes: 12 additions & 0 deletions src/main/java/org/folio/domain/dto/UserType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.folio.domain.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Getter
public enum UserType {
SHADOW("shadow");

private final String value;
}

This file was deleted.

12 changes: 12 additions & 0 deletions src/main/java/org/folio/service/RequestService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.folio.service;

import java.util.Collection;

import org.folio.domain.RequestWrapper;
import org.folio.domain.dto.Request;

public interface RequestService {

RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId,
Collection<String> lendingTenantIds);
}
12 changes: 12 additions & 0 deletions src/main/java/org/folio/service/TenantService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.folio.service;

import java.util.List;
import java.util.Optional;

import org.folio.domain.dto.EcsTlr;

public interface TenantService {
Optional<String> getBorrowingTenant(EcsTlr ecsTlr);

List<String> getLendingTenants(EcsTlr ecsTlr);
}
9 changes: 9 additions & 0 deletions src/main/java/org/folio/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.folio.service;

import org.folio.domain.dto.User;

public interface UserService {
User createShadowUser(User realUser, String tenantId);

User findUser(String userId, String tenantId);
}
93 changes: 53 additions & 40 deletions src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package org.folio.service.impl;

import static java.lang.String.format;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.folio.client.feign.CirculationClient;
import org.folio.domain.RequestWrapper;
import org.folio.domain.dto.EcsTlr;
import org.folio.domain.dto.Request;
import org.folio.domain.entity.EcsTlrEntity;
import org.folio.domain.mapper.EcsTlrMapper;
import org.folio.domain.strategy.TenantPickingStrategy;
import org.folio.exception.RequestCreatingException;
import org.folio.exception.TenantPickingException;
import org.folio.repository.EcsTlrRepository;
import org.folio.service.EcsTlrService;
import org.folio.service.TenantScopedExecutionService;
import org.folio.service.RequestService;
import org.folio.service.TenantService;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
Expand All @@ -28,9 +26,8 @@ public class EcsTlrServiceImpl implements EcsTlrService {

private final EcsTlrRepository ecsTlrRepository;
private final EcsTlrMapper requestsMapper;
private final CirculationClient circulationClient;
private final TenantScopedExecutionService tenantScopedExecutionService;
private final TenantPickingStrategy tenantPickingStrategy;
private final TenantService tenantService;
private final RequestService requestService;

@Override
public Optional<EcsTlr> get(UUID id) {
Expand All @@ -42,24 +39,16 @@ public Optional<EcsTlr> get(UUID id) {

@Override
public EcsTlr create(EcsTlr ecsTlr) {
log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr);
final String instanceId = ecsTlr.getInstanceId();
log.info("create:: creating ECS TLR {} for instance {} and requester {}", ecsTlr.getId(),
ecsTlr.getInstanceId(), ecsTlr.getRequesterId());

List<String> tenantIds = tenantPickingStrategy.findTenants(instanceId);
if (tenantIds.isEmpty()) {
log.error("create:: failed to find tenants for instance: {}", instanceId);
throw new TenantPickingException("Failed to find tenants for instance " + instanceId);
}
for (String tenantId : tenantIds) {
try {
return createRequest(ecsTlr, tenantId);
} catch (Exception e) {
log.error("create:: failed to create a request for tenant {}: {}", tenantId, e.getMessage());
log.debug("create:: ", e);
}
}
throw new RequestCreatingException(format(
"Failed to create a request for instanceId %s in tenants %s", instanceId, tenantIds));
String borrowingTenantId = getBorrowingTenant(ecsTlr);
Collection<String> lendingTenantIds = getLendingTenants(ecsTlr);
RequestWrapper secondaryRequest = requestService.createSecondaryRequest(
requestsMapper.mapDtoToRequest(ecsTlr), borrowingTenantId, lendingTenantIds);
updateEcsTlr(ecsTlr, secondaryRequest);

return save(ecsTlr);
}

@Override
Expand All @@ -84,23 +73,47 @@ public boolean delete(UUID requestId) {
return false;
}

private EcsTlr createRequest(EcsTlr ecsTlr, String tenantId) {
log.info("createRequest:: creating request for ECS TLR {} in tenant {}", ecsTlr.getId(), tenantId);
private String getBorrowingTenant(EcsTlr ecsTlr) {
log.info("getBorrowingTenant:: getting borrowing tenant");
final String borrowingTenantId = tenantService.getBorrowingTenant(ecsTlr)
.orElseThrow(() -> new TenantPickingException("Failed to get borrowing tenant"));
log.info("getBorrowingTenant:: borrowing tenant: {}", borrowingTenantId);

return borrowingTenantId;
}

private Collection<String> getLendingTenants(EcsTlr ecsTlr) {
final String instanceId = ecsTlr.getInstanceId();
log.info("getLendingTenants:: looking for lending tenants for instance {}", instanceId);
List<String> tenantIds = tenantService.getLendingTenants(ecsTlr);
if (tenantIds.isEmpty()) {
log.error("getLendingTenants:: failed to find lending tenants for instance: {}", instanceId);
throw new TenantPickingException("Failed to find lending tenants for instance " + instanceId);
}

log.info("getLendingTenants:: lending tenants found: {}", tenantIds);
return tenantIds;
}

Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr);
Request createdRequest = tenantScopedExecutionService.execute(tenantId,
() -> circulationClient.createInstanceRequest(mappedRequest));
private EcsTlr save(EcsTlr ecsTlr) {
log.info("save:: saving ECS TLR {}", ecsTlr.getId());
EcsTlrEntity updatedEcsTlr = ecsTlrRepository.save(requestsMapper.mapDtoToEntity(ecsTlr));
log.info("save:: saved ECS TLR {}", ecsTlr.getId());
log.debug("save:: ECS TLR: {}", () -> ecsTlr);

log.info("createRequest:: request created: {}", createdRequest.getId());
log.debug("createRequest:: request: {}", () -> createdRequest);
return requestsMapper.mapEntityToDto(updatedEcsTlr);
}

ecsTlr.secondaryRequestTenantId(tenantId)
.secondaryRequestId(createdRequest.getId())
.itemId(createdRequest.getItemId());
private static void updateEcsTlr(EcsTlr ecsTlr,
RequestWrapper secondaryRequest) {

log.debug("createRequest:: updating ECS TLR: {}", () -> ecsTlr);
log.info("updateEcsTlr:: updating ECS TLR in memory");
ecsTlr.secondaryRequestTenantId(secondaryRequest.tenantId())
.secondaryRequestId(secondaryRequest.request().getId())
.itemId(secondaryRequest.request().getItemId());

return requestsMapper.mapEntityToDto(ecsTlrRepository.save(
requestsMapper.mapDtoToEntity(ecsTlr)));
log.info("updateEcsTlr:: ECS TLR updated in memory");
log.debug("updateEcsTlr:: ECS TLR: {}", () -> ecsTlr);
}

}
73 changes: 73 additions & 0 deletions src/main/java/org/folio/service/impl/RequestServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.folio.service.impl;

import static java.lang.String.format;

import java.util.Collection;

import org.folio.client.feign.CirculationClient;
import org.folio.domain.RequestWrapper;
import org.folio.domain.dto.Request;
import org.folio.domain.dto.User;
import org.folio.exception.RequestCreatingException;
import org.folio.service.RequestService;
import org.folio.service.TenantScopedExecutionService;
import org.folio.service.UserService;
import org.springframework.stereotype.Service;

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

@Service
@RequiredArgsConstructor
@Log4j2
public class RequestServiceImpl implements RequestService {
private final TenantScopedExecutionService tenantScopedExecutionService;
private final CirculationClient circulationClient;
private final UserService userService;

@Override
public RequestWrapper createSecondaryRequest(Request request, String borrowingTenantId,
Collection<String> lendingTenantIds) {

log.info("createSecondaryRequest:: attempting to create secondary request in one of potential " +
"lending tenants: {}", lendingTenantIds);
final String requesterId = request.getRequesterId();

log.info("createSecondaryRequest:: looking for requester {} in borrowing tenant ({})",
requesterId, borrowingTenantId);
User realRequester = userService.findUser(requesterId, borrowingTenantId);

for (String lendingTenantId : lendingTenantIds) {
try {
log.info("createSecondaryRequest:: attempting to create shadow requester {} in lending tenant {}",
requesterId, lendingTenantId);
userService.createShadowUser(realRequester, lendingTenantId);
return createSecondaryRequest(request, lendingTenantId);
} catch (Exception e) {
log.error("createSecondaryRequest:: failed to create secondary request in lending tenant {}: {}",
lendingTenantId, e.getMessage());
log.debug("createSecondaryRequest:: ", e);
}
}

String errorMessage = format(
"Failed to create secondary request for instance %s in all potential lending tenants: %s",
request.getInstanceId(), lendingTenantIds);
log.error("createSecondaryRequest:: {}", errorMessage);
throw new RequestCreatingException(errorMessage);
}

private RequestWrapper createSecondaryRequest(Request request, String lendingTenantId) {
final String requestId = request.getId();
log.info("createSecondaryRequest:: creating secondary request {} in lending tenant {}",
requestId, lendingTenantId);
Request secondaryRequest = tenantScopedExecutionService.execute(lendingTenantId,
() -> circulationClient.createInstanceRequest(request));
log.info("createSecondaryRequest:: secondary request {} created in lending tenant {}",
requestId, lendingTenantId);
log.debug("createSecondaryRequest:: secondary request: {}", () -> secondaryRequest);

return new RequestWrapper(secondaryRequest, lendingTenantId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public <T> T execute(String tenantId, Callable<T> action) {
try (var x = new FolioExecutionContextSetter(moduleMetadata, headers)) {
return action.call();
} catch (Exception e) {
log.error("execute:: tenantId: {}", tenantId, e);
log.error("execute:: execution failed for tenant {}: {}", tenantId, e.getMessage());
throw new TenantScopedExecutionException(e, tenantId);
}
}
Expand Down
Loading

0 comments on commit f773328

Please sign in to comment.