Skip to content

Commit

Permalink
Merge branch 'master' into MODTLR-19
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderkurash authored Mar 1, 2024
2 parents 01fbb49 + 74109eb commit 277d7c3
Show file tree
Hide file tree
Showing 24 changed files with 871 additions and 129 deletions.
6 changes: 5 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
"permissionsRequired": ["tlr.ecs-tlr.post"],
"modulePermissions": [
"circulation.requests.instances.item.post",
"search.instances.collection.get"
"circulation.requests.item.post",
"search.instances.collection.get",
"users.item.get",
"users.collection.get",
"users.item.post"
]
},
{
Expand Down
7 changes: 5 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,12 @@
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);

@PostMapping("/requests")
Request createRequest(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.

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

import java.util.Collection;

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

public interface RequestService {
RequestWrapper createPrimaryRequest(Request request, String borrowingTenantId);

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);
}
110 changes: 70 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,20 @@
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 +27,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 +40,18 @@ public Optional<EcsTlr> get(UUID id) {

@Override
public EcsTlr create(EcsTlr ecsTlr) {
log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr);
final String instanceId = ecsTlr.getInstanceId();

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));
log.info("create:: creating ECS TLR {} for instance {} and requester {}", ecsTlr.getId(),
ecsTlr.getInstanceId(), ecsTlr.getRequesterId());

String borrowingTenantId = getBorrowingTenant(ecsTlr);
Collection<String> lendingTenantIds = getLendingTenants(ecsTlr);
RequestWrapper secondaryRequest = requestService.createSecondaryRequest(
requestsMapper.mapDtoToRequest(ecsTlr), borrowingTenantId, lendingTenantIds);
RequestWrapper primaryRequest = requestService.createPrimaryRequest(
buildPrimaryRequest(secondaryRequest.request()), borrowingTenantId);
updateEcsTlr(ecsTlr, primaryRequest, secondaryRequest);

return save(ecsTlr);
}

@Override
Expand All @@ -84,23 +76,61 @@ 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);
}

Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr);
Request createdRequest = tenantScopedExecutionService.execute(tenantId,
() -> circulationClient.createInstanceRequest(mappedRequest));
log.info("getLendingTenants:: lending tenants found: {}", tenantIds);
return tenantIds;
}

log.info("createRequest:: request created: {}", createdRequest.getId());
log.debug("createRequest:: request: {}", () -> createdRequest);
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);

ecsTlr.secondaryRequestTenantId(tenantId)
.secondaryRequestId(createdRequest.getId())
.itemId(createdRequest.getItemId());
return requestsMapper.mapEntityToDto(updatedEcsTlr);
}

log.debug("createRequest:: updating ECS TLR: {}", () -> ecsTlr);
private static Request buildPrimaryRequest(Request secondaryRequest) {
return new Request()
.id(secondaryRequest.getId())
.instanceId(secondaryRequest.getInstanceId())
.requesterId(secondaryRequest.getRequesterId())
.requestDate(secondaryRequest.getRequestDate())
.requestLevel(Request.RequestLevelEnum.TITLE)
.requestType(Request.RequestTypeEnum.HOLD)
.fulfillmentPreference(Request.FulfillmentPreferenceEnum.HOLD_SHELF)
.pickupServicePointId(secondaryRequest.getPickupServicePointId());
}

private static void updateEcsTlr(EcsTlr ecsTlr, RequestWrapper primaryRequest,
RequestWrapper secondaryRequest) {

return requestsMapper.mapEntityToDto(ecsTlrRepository.save(
requestsMapper.mapDtoToEntity(ecsTlr)));
log.info("updateEcsTlr:: updating ECS TLR in memory");
ecsTlr.primaryRequestTenantId(primaryRequest.tenantId())
.primaryRequestId(primaryRequest.request().getId())
.secondaryRequestTenantId(secondaryRequest.tenantId())
.secondaryRequestId(secondaryRequest.request().getId())
.itemId(secondaryRequest.request().getItemId());

log.info("updateEcsTlr:: ECS TLR updated in memory");
log.debug("updateEcsTlr:: ECS TLR: {}", () -> ecsTlr);
}

}
87 changes: 87 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,87 @@
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 createPrimaryRequest(Request request, String borrowingTenantId) {
final String requestId = request.getId();
log.info("createPrimaryRequest:: creating primary request {} in borrowing tenant {}",
requestId, borrowingTenantId);
Request primaryRequest = tenantScopedExecutionService.execute(borrowingTenantId,
() -> circulationClient.createRequest(request));
log.info("createPrimaryRequest:: primary request {} created in borrowing tenant {}",
requestId, borrowingTenantId);
log.debug("createPrimaryRequest:: primary request: {}", () -> primaryRequest);

return new RequestWrapper(primaryRequest, borrowingTenantId);
}

@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 277d7c3

Please sign in to comment.