From 2805baad0b630f37d6d86deb5e0e7f62e8c4e733 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 24 Jan 2024 15:09:18 +0200 Subject: [PATCH 01/16] MODTLR-10 Basic implementation and tests --- descriptors/ModuleDescriptor-template.json | 4 +- pom.xml | 5 + .../org/folio/client/CirculationClient.java | 13 + .../folio/controller/EcsTlrController.java | 2 +- .../org/folio/domain/mapper/EcsTlrMapper.java | 15 +- .../java/org/folio/service/EcsTlrService.java | 2 +- .../service/TenantScopedExecutionService.java | 8 + .../folio/service/impl/EcsTlrServiceImpl.java | 13 +- .../TenantScopedExecutionServiceImpl.java | 39 ++ src/main/resources/application.yml | 4 + src/main/resources/swagger.api/ecs-tlr.yaml | 4 +- .../swagger.api/schemas/override-blocks.json | 57 +++ .../schemas/request-search-index.json | 35 ++ .../swagger.api/schemas/request.json | 395 ++++++++++++++++++ .../resources/swagger.api/schemas/tags.json | 16 + .../resources/swagger.api/schemas/uuid.json | 5 + src/test/java/org/folio/api/BaseIT.java | 55 ++- .../java/org/folio/api/EcsTlrApiTest.java | 93 ++++- .../controller/EcsTlrControllerTest.java | 3 +- .../org/folio/service/EcsTlrServiceTest.java | 2 +- 20 files changed, 745 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/folio/client/CirculationClient.java create mode 100644 src/main/java/org/folio/service/TenantScopedExecutionService.java create mode 100644 src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java create mode 100644 src/main/resources/swagger.api/schemas/override-blocks.json create mode 100644 src/main/resources/swagger.api/schemas/request-search-index.json create mode 100644 src/main/resources/swagger.api/schemas/request.json create mode 100644 src/main/resources/swagger.api/schemas/tags.json create mode 100644 src/main/resources/swagger.api/schemas/uuid.json diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index 7d4581ed..fb89305c 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -16,7 +16,9 @@ "methods": ["POST"], "pathPattern": "/tlr/ecs-tlr", "permissionsRequired": ["tlr.ecs-tlr.post"], - "modulePermissions": [] + "modulePermissions": [ + "circulation.requests.item.post" + ] } ] }, diff --git a/pom.xml b/pom.xml index 2f422aa0..043b812f 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,11 @@ provided + + org.springframework + spring-webflux + + org.springframework.boot diff --git a/src/main/java/org/folio/client/CirculationClient.java b/src/main/java/org/folio/client/CirculationClient.java new file mode 100644 index 00000000..043dc9df --- /dev/null +++ b/src/main/java/org/folio/client/CirculationClient.java @@ -0,0 +1,13 @@ +package org.folio.client; + +import org.folio.domain.dto.Request; +import org.folio.spring.config.FeignClientConfiguration; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.PostMapping; + +@FeignClient(name = "circulation", url = "${folio.okapi-url}", configuration = FeignClientConfiguration.class) +public interface CirculationClient { + + @PostMapping("/circulation/requests") + Request createTitleLevelRequest(Request request); +} diff --git a/src/main/java/org/folio/controller/EcsTlrController.java b/src/main/java/org/folio/controller/EcsTlrController.java index 9fe5e947..7f461ce5 100644 --- a/src/main/java/org/folio/controller/EcsTlrController.java +++ b/src/main/java/org/folio/controller/EcsTlrController.java @@ -34,6 +34,6 @@ public ResponseEntity getEcsTlrById(UUID requestId) { public ResponseEntity postEcsTlr(EcsTlr ecsTlr) { log.debug("postEcsTlr:: parameters ecsTlr: {}", ecsTlr); - return ResponseEntity.status(CREATED).body(ecsTlrService.post(ecsTlr)); + return ResponseEntity.status(CREATED).body(ecsTlrService.create(ecsTlr)); } } diff --git a/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java b/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java index f4d97f9d..cb06de46 100644 --- a/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java +++ b/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java @@ -1,6 +1,7 @@ package org.folio.domain.mapper; import org.folio.domain.dto.EcsTlr; +import org.folio.domain.dto.Request; import org.folio.domain.entity.EcsTlrEntity; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -36,17 +37,19 @@ default EcsTlr.FulfillmentPreferenceEnum mapFulfillmentPreference(String fulfill } @Named("RequestTypeToString") - default String mapRequestTypeToString(EcsTlr.RequestTypeEnum requestTypeEnum) { - return requestTypeEnum != null ? requestTypeEnum.getValue() : null; + default String mapRequestType(EcsTlr.RequestTypeEnum requestType) { + return requestType != null ? requestType.getValue() : null; } @Named("RequestLevelToString") - default String mapRequestLevelToString(EcsTlr.RequestLevelEnum requestLevelEnum) { - return requestLevelEnum != null ? requestLevelEnum.getValue() : null; + default String mapRequestLevel(EcsTlr.RequestLevelEnum requestLevel) { + return requestLevel != null ? requestLevel.getValue() : null; } @Named("FulfillmentPreferenceToString") - default String mapFulfillmentPreferenceToString(EcsTlr.FulfillmentPreferenceEnum fulfillmentPreferenceEnum) { - return fulfillmentPreferenceEnum != null ? fulfillmentPreferenceEnum.getValue() : null; + default String mapFulfillmentPreference(EcsTlr.FulfillmentPreferenceEnum fulfillmentPreference) { + return fulfillmentPreference != null ? fulfillmentPreference.getValue() : null; } + + Request mapDtoToRequest(EcsTlr ecsTlr); } diff --git a/src/main/java/org/folio/service/EcsTlrService.java b/src/main/java/org/folio/service/EcsTlrService.java index 4d7da52a..bbee5bb8 100644 --- a/src/main/java/org/folio/service/EcsTlrService.java +++ b/src/main/java/org/folio/service/EcsTlrService.java @@ -7,5 +7,5 @@ public interface EcsTlrService { Optional get(UUID requestId); - EcsTlr post(EcsTlr ecsTlr); + EcsTlr create(EcsTlr ecsTlr); } diff --git a/src/main/java/org/folio/service/TenantScopedExecutionService.java b/src/main/java/org/folio/service/TenantScopedExecutionService.java new file mode 100644 index 00000000..d20bf68c --- /dev/null +++ b/src/main/java/org/folio/service/TenantScopedExecutionService.java @@ -0,0 +1,8 @@ +package org.folio.service; + +import java.util.concurrent.Callable; + +public interface TenantScopedExecutionService { + + T execute(String tenantId, Callable action); +} diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 43d20595..058312f4 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -3,9 +3,12 @@ import java.util.Optional; import java.util.UUID; +import org.folio.client.CirculationClient; import org.folio.domain.dto.EcsTlr; +import org.folio.domain.dto.Request; import org.folio.domain.mapper.EcsTlrMapper; import org.folio.repository.EcsTlrRepository; +import org.folio.service.TenantScopedExecutionService; import org.folio.service.EcsTlrService; import org.springframework.stereotype.Service; @@ -19,6 +22,8 @@ public class EcsTlrServiceImpl implements EcsTlrService { private final EcsTlrRepository ecsTlrRepository; private final EcsTlrMapper requestsMapper; + private final CirculationClient circulationClient; + private final TenantScopedExecutionService tenantScopedExecutionService; @Override public Optional get(UUID id) { @@ -29,8 +34,12 @@ public Optional get(UUID id) { } @Override - public EcsTlr post(EcsTlr ecsTlr) { - log.debug("post:: parameters ecsTlr: {}", () -> ecsTlr); + public EcsTlr create(EcsTlr ecsTlr) { + log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); + Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr); + Request cretedRequest = tenantScopedExecutionService.execute("dummy-tenant", // TODO: replace with real tenantId + () -> circulationClient.createTitleLevelRequest(mappedRequest)); + log.info("create:: title-level request created: {}", cretedRequest.getId()); return requestsMapper.mapEntityToDto(ecsTlrRepository.save( requestsMapper.mapDtoToEntity(ecsTlr))); diff --git a/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java new file mode 100644 index 00000000..4248458b --- /dev/null +++ b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java @@ -0,0 +1,39 @@ +package org.folio.service.impl; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +import org.folio.service.TenantScopedExecutionService; +import org.folio.spring.FolioExecutionContext; +import org.folio.spring.FolioModuleMetadata; +import org.folio.spring.integration.XOkapiHeaders; +import org.folio.spring.scope.FolioExecutionContextSetter; +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; + +@Service +@RequiredArgsConstructor +@Log4j2 +public class TenantScopedExecutionServiceImpl implements TenantScopedExecutionService { + + private final FolioModuleMetadata moduleMetadata; + private final FolioExecutionContext executionContext; + + @Override + public T execute(String tenantId, Callable action) { + log.info("execute:: tenantId={}", tenantId); + Map> headers = executionContext.getAllHeaders(); + headers.put(XOkapiHeaders.TENANT, List.of(tenantId)); + + try (var x = new FolioExecutionContextSetter(moduleMetadata, headers)) { + return action.call(); + } catch (Exception e) { + log.error("execute:: tenantId={}", tenantId, e); + throw new RuntimeException(e); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5fa89cd8..c3fef02e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -43,6 +43,10 @@ folio: enabled: true environment: ${ENV:folio} okapi-url: ${OKAPI_URL:http://okapi:9130} + logging: + feign: + enabled: true + level: full management: endpoints: web: diff --git a/src/main/resources/swagger.api/ecs-tlr.yaml b/src/main/resources/swagger.api/ecs-tlr.yaml index 3a2064a0..657e0354 100644 --- a/src/main/resources/swagger.api/ecs-tlr.yaml +++ b/src/main/resources/swagger.api/ecs-tlr.yaml @@ -45,7 +45,9 @@ components: ecs-tlr: $ref: 'schemas/EcsTlr.yaml#/EcsTlr' errorResponse: - $ref: schemas/errors.json + $ref: 'schemas/errors.json' + request: + $ref: 'schemas/request.json' parameters: requestId: name: requestId diff --git a/src/main/resources/swagger.api/schemas/override-blocks.json b/src/main/resources/swagger.api/schemas/override-blocks.json new file mode 100644 index 00000000..51985abd --- /dev/null +++ b/src/main/resources/swagger.api/schemas/override-blocks.json @@ -0,0 +1,57 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "Blocks to override (e.g. during checkout or renewal)", + "properties": { + "itemNotLoanableBlock": { + "description": "'Item not loanable' block", + "type": "object", + "properties": { + "dueDate": { + "description": "Due date for a new loan", + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false, + "required": [ + "dueDate" + ] + }, + "patronBlock": { + "description": "Automated patron block", + "type": "object", + "additionalProperties": false + }, + "itemLimitBlock": { + "description": "Item limit block", + "type": "object", + "additionalProperties": false + }, + "renewalBlock": { + "description": "Renewal block", + "type": "object", + "additionalProperties": false + }, + "renewalDueDateRequiredBlock": { + "description": "Override renewal block which requires due date field", + "type": "object", + "properties": { + "dueDate": { + "description": "Due date for a new loan", + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false, + "required": [ + "dueDate" + ] + }, + "comment": { + "description": "Reason for override", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/src/main/resources/swagger.api/schemas/request-search-index.json b/src/main/resources/swagger.api/schemas/request-search-index.json new file mode 100644 index 00000000..25ff8c84 --- /dev/null +++ b/src/main/resources/swagger.api/schemas/request-search-index.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Request fields used for search", + "type": "object", + "properties": { + "callNumberComponents": { + "type": "object", + "description": "Effective call number components", + "properties": { + "callNumber": { + "type": "string", + "description": "Effective Call Number is an identifier assigned to an item or its holding and associated with the item." + }, + "prefix": { + "type": "string", + "description": "Effective Call Number Prefix is the prefix of the identifier assigned to an item or its holding and associated with the item." + }, + "suffix": { + "type": "string", + "description": "Effective Call Number Suffix is the suffix of the identifier assigned to an item or its holding and associated with the item." + } + }, + "additionalProperties": false + }, + "shelvingOrder": { + "type": "string", + "description": "A system generated normalization of the call number that allows for call number sorting in reports and search results" + }, + "pickupServicePointName": { + "description": "The name of the request pickup service point", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/src/main/resources/swagger.api/schemas/request.json b/src/main/resources/swagger.api/schemas/request.json new file mode 100644 index 00000000..cb43c1f3 --- /dev/null +++ b/src/main/resources/swagger.api/schemas/request.json @@ -0,0 +1,395 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "A request for an item", + "description": "Request for an item that might be at a different location or already checked out to another patron", + "type": "object", + "properties": { + "id": { + "description": "UUID of the request", + "type": "string", + "$ref": "uuid.json" + }, + "requestType": { + "description": "Whether the item should be held upon return, recalled or paged for", + "type": "string", + "enum": ["Hold", "Recall", "Page"] + }, + "requestLevel": { + "description": "Level of the request - Item or Title", + "type": "string", + "enum": ["Item", "Title"] + }, + "requestDate": { + "description": "Date the request was made", + "type": "string", + "format": "date-time" + }, + "patronComments": { + "description": "Comments made by the patron", + "type": "string" + }, + "requesterId": { + "description": "ID of the user who made the request", + "type": "string", + "$ref": "uuid.json" + }, + "proxyUserId": { + "description": "ID of the user representing a proxy for the patron", + "type": "string", + "$ref": "uuid.json" + }, + "instanceId": { + "description": "ID of the instance being requested", + "type": "string", + "$ref": "uuid.json" + }, + "holdingsRecordId": { + "description": "ID of the holdings record being requested", + "type": "string", + "$ref": "uuid.json" + }, + "itemId": { + "description": "ID of the item being requested", + "type": "string", + "$ref": "uuid.json" + }, + "status": { + "description": "Status of the request", + "type": "string", + "enum": [ + "Open - Not yet filled", + "Open - Awaiting pickup", + "Open - In transit", + "Open - Awaiting delivery", + "Closed - Filled", + "Closed - Cancelled", + "Closed - Unfilled", + "Closed - Pickup expired" + ] + }, + "cancellationReasonId": { + "description": "The id of the request reason", + "type": "string", + "$ref": "uuid.json" + }, + "cancelledByUserId": { + "description": "The id of the user that cancelled the request", + "type": "string", + "$ref": "uuid.json" + }, + "cancellationAdditionalInformation": { + "description": "Additional information about a cancellation", + "type": "string" + }, + "cancelledDate": { + "description": "Date the request was cancelled", + "type": "string", + "format": "date-time" + }, + "position": { + "description": "position of the request in a per-item request queue", + "type": "integer", + "minimum": 1 + }, + "instance": { + "description": "Copy of some instance metadata (used for searching and sorting)", + "type": "object", + "properties": { + "title": { + "description": "title of the item", + "type": "string" + }, + "identifiers": { + "type": "array", + "description": "An extensible set of name-value pairs of identifiers associated with the resource", + "minItems": 0, + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "description": "Resource identifier value" + }, + "identifierTypeId": { + "type": "string", + "description": "UUID of resource identifier type (e.g. ISBN, ISSN, LCCN, CODEN, Locally defined identifiers)", + "$ref": "uuid.json" + } + }, + "additionalProperties": false, + "required": [ + "value", + "identifierTypeId" + ] + } + } + } + }, + "item": { + "description": "Copy of some item metadata (used for searching and sorting)", + "type": "object", + "properties": { + "barcode": { + "description": "barcode of the item", + "type": "string" + } + }, + "additionalProperties": false + }, + "requester": { + "description": "Copy of some requesting patron metadata (used for searching and sorting), will be taken from the user referred to by the requesterId", + "readonly": true, + "type": "object", + "properties": { + "firstName": { + "description": "first name of the patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "lastName": { + "description": "last name of the patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "middleName": { + "description": "middle name of the patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "barcode": { + "description": "barcode of the patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "patronGroupId": { + "description": "UUID for the patron group that this user belongs to", + "type": "string", + "readonly": true, + "$ref": "uuid.json" + }, + "patronGroup": { + "description": "record for the user's patron group", + "type": "object", + "additionalProperties": false, + "readonly": true, + "properties": { + "id": { + "description": "ID of the patron group", + "type": "string", + "readonly": true, + "$ref": "uuid.json" + }, + "group": { + "description": "The unique name of the patron group", + "type": "string", + "readonly": true + }, + "desc": { + "description": "A description of the patron group", + "type": "string", + "readonly": true + } + } + } + }, + "additionalProperties": false + }, + "proxy": { + "description": "Copy of some proxy patron metadata (used for searching and sorting), will be taken from the user referred to by the proxyUserId", + "readonly": true, + "type": "object", + "properties": { + "firstName": { + "description": "first name of the proxy patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "lastName": { + "description": "last name of the proxy patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "middleName": { + "description": "middle name of the proxy patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "barcode": { + "description": "barcode of the proxy patron (read only, defined by the server)", + "type": "string", + "readonly": true + }, + "patronGroupId": { + "description": "UUID for the patrongroup that this user belongs to", + "type": "string", + "readonly": true, + "$ref": "uuid.json" + }, + "patronGroup": { + "description": "record for the user's patrongroup", + "type": "object", + "readonly": true, + "additionalProperties": false, + "properties": { + "id": { + "description": "ID of the patrongroup", + "type": "string", + "readonly": true, + "$ref": "uuid.json" + }, + "group": { + "description": "The unique name of the patrongroup", + "type": "string", + "readonly": true + }, + "desc": { + "description": "A description of the patrongroup", + "type": "string", + "readonly": true + } + } + } + }, + "additionalProperties": false + }, + "fulfillmentPreference": { + "description": "How should the request be fulfilled (whether the item should be kept on the hold shelf for collection or delivered to the requester)", + "type": "string", + "enum": ["Hold Shelf", "Delivery"] + }, + "deliveryAddressTypeId": { + "description": "Deliver to the address of this type, for the requesting patron", + "type": "string", + "$ref": "uuid.json" + }, + "deliveryAddress": { + "description": "Address the item is to be delivered to (derived from requester information)", + "type": "object", + "readonly": true, + "properties": { + "addressLine1": { + "description": "Address line 1", + "type": "string", + "readonly": true + }, + "addressLine2": { + "description": "Address line 2", + "type": "string", + "readonly": true + }, + "city": { + "description": "City name", + "type": "string", + "readonly": true + }, + "region": { + "description": "Region", + "type": "string", + "readonly": true + }, + "postalCode": { + "description": "Postal code", + "type": "string", + "readonly": true + }, + "countryId": { + "description": "Country code", + "type": "string", + "readonly": true + }, + "addressTypeId": { + "description": "Type of address (refers to address types)", + "type": "string", + "readonly": true, + "$ref": "uuid.json" + } + }, + "additionalProperties": false + }, + "requestExpirationDate": { + "description": "Date when the request expires", + "type": "string", + "format": "date-time" + }, + "holdShelfExpirationDate": { + "description": "Date when an item returned to the hold shelf expires", + "type": "string", + "format": "date-time" + }, + "pickupServicePointId": { + "description": "The ID of the Service Point where this request can be picked up", + "type": "string", + "$ref": "uuid.json" + }, + "pickupServicePoint": { + "description": "The full object of the Service Point record from pickupServicePointId", + "additionalProperties": false, + "readonly": true, + "properties": { + "name": { + "description": "Unique name for the service point", + "type": "string", + "readonly": true + }, + "code": { + "description": "Unique code for the service point", + "type": "string", + "readonly": true + }, + "discoveryDisplayName": { + "description": "Human-readable name for the service point", + "type": "string", + "readonly": true + }, + "description": { + "description": "Description of the service point", + "type": "string", + "readonly": true + }, + "shelvingLagTime": { + "description": "Shelving lag time", + "type": "integer", + "readonly": true + }, + "pickupLocation": { + "description": "Is this service point a pickup location?", + "type": "boolean", + "readonly": true + } + } + }, + "tags": { + "type": "object", + "description": "Tags", + "$ref": "tags.json" + }, + "metadata": { + "description": "Metadata about creation and changes to requests, provided by the server (client should not provide)", + "type": "object", + "$ref": "metadata.json" + }, + "requestProcessingParameters": { + "type": "object", + "description": "Additional parameters used for request processing and discarded afterwards. Not part of request record.", + "properties": { + "overrideBlocks": { + "type": "object", + "description": "Blocks to override if user has corresponding permissions", + "$ref": "override-blocks.json" + } + } + }, + "searchIndex": { + "description": "Request fields used for search", + "type": "object", + "$ref": "request-search-index.json" + } + }, + "additionalProperties": false, + "required": [ + "requesterId", + "requestType", + "requestDate", + "fulfillmentPreference" + ] +} diff --git a/src/main/resources/swagger.api/schemas/tags.json b/src/main/resources/swagger.api/schemas/tags.json new file mode 100644 index 00000000..cc7cfcfc --- /dev/null +++ b/src/main/resources/swagger.api/schemas/tags.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "tags", + "description": "List of simple tags that can be added to an object", + "type": "object", + "properties": { + "tagList": { + "description": "List of tags", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false +} diff --git a/src/main/resources/swagger.api/schemas/uuid.json b/src/main/resources/swagger.api/schemas/uuid.json new file mode 100644 index 00000000..1f907f9e --- /dev/null +++ b/src/main/resources/swagger.api/schemas/uuid.json @@ -0,0 +1,5 @@ +{ + "description": "A universally unique identifier (UUID), this is a 128-bit number used to identify a record and is shown in hex with dashes, for example 6312d172-f0cf-40f6-b27d-9fa8feaf332f; the UUID version must be from 1-5; see https://dev.folio.org/guides/uuids/", + "type": "string", + "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" +} diff --git a/src/test/java/org/folio/api/BaseIT.java b/src/test/java/org/folio/api/BaseIT.java index e34adfc0..c324081c 100644 --- a/src/test/java/org/folio/api/BaseIT.java +++ b/src/test/java/org/folio/api/BaseIT.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.tomakehurst.wiremock.WireMockServer; import lombok.SneakyThrows; import org.folio.spring.integration.XOkapiHeaders; @@ -14,20 +15,25 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.util.TestSocketUtils; +import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.reactive.function.BodyInserters; import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Testcontainers; import java.util.List; +import java.util.UUID; import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -38,14 +44,18 @@ public class BaseIT { @Autowired protected MockMvc mockMvc; - public static WireMockServer wireMockServer; + protected static WireMockServer wireMockServer; protected static final String TOKEN = "test_token"; - public static final String TENANT = "diku"; - protected static PostgreSQLContainer postgresDBContainer = new PostgreSQLContainer<>("postgres:12-alpine"); - public final static int WIRE_MOCK_PORT = TestSocketUtils.findAvailableTcpPort(); - protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL) + protected static final String TENANT = "diku"; + private static final PostgreSQLContainer postgresDBContainer = new PostgreSQLContainer<>("postgres:12-alpine"); + private static final int WIRE_MOCK_PORT = TestSocketUtils.findAvailableTcpPort(); + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + @LocalServerPort + private int serverPort; + private WebTestClient webClient; static { postgresDBContainer.start(); @@ -69,7 +79,7 @@ static void tearDown() { @SneakyThrows protected static void setUpTenant(MockMvc mockMvc) { - mockMvc.perform(post("/_/tenant") + mockMvc.perform(MockMvcRequestBuilders.post("/_/tenant") .content(asJsonString(new TenantAttributes().moduleTo("mod-tlr"))) .headers(defaultHeaders()) .contentType(APPLICATION_JSON)).andExpect(status().isNoContent()); @@ -102,4 +112,33 @@ public void initialize(@NotNull ConfigurableApplicationContext applicationContex } } + protected WebTestClient webClient() { + if (webClient == null) { + webClient = WebTestClient.bindToServer() + .baseUrl("http://localhost:" + serverPort).build(); + } + return webClient; + } + + protected WebTestClient.RequestBodySpec buildRequest(HttpMethod method, String uri) { + return webClient().method(method) + .uri(uri) + .accept(APPLICATION_JSON) + .contentType(APPLICATION_JSON) + .header(XOkapiHeaders.TENANT, TENANT) + .header(XOkapiHeaders.URL, wireMockServer.baseUrl()) + .header(XOkapiHeaders.TOKEN, TOKEN) + .header(XOkapiHeaders.USER_ID, UUID.randomUUID().toString()); + } + + protected WebTestClient.ResponseSpec doPost(String uri, Object payload) { + return buildRequest(HttpMethod.POST, uri) + .body(BodyInserters.fromValue(payload)) + .exchange(); + } + + protected static String randomId() { + return UUID.randomUUID().toString(); + } + } diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index 71e8e898..c24dad22 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -1,20 +1,109 @@ package org.folio.api; +import org.apache.http.HttpStatus; +import org.folio.domain.dto.EcsTlr; +import org.folio.spring.FolioExecutionContext; +import org.folio.spring.FolioModuleMetadata; +import org.folio.spring.scope.FolioExecutionContextSetter; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.MediaType; + +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.jsonResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; +import static java.util.stream.Collectors.toMap; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.github.tomakehurst.wiremock.client.WireMock; + class EcsTlrApiTest extends BaseIT { - private static final String TLR_URL = "/tlr/ecs-tlr/"; + private static final String TLR_URL = "/tlr/ecs-tlr"; + private static final String ANOTHER_TENANT = "dummy-tenant"; + private static final String TENANT_HEADER = "x-okapi-tenant"; + + @Autowired + private FolioExecutionContext context; + @Autowired + private FolioModuleMetadata moduleMetadata; + @Autowired + private TestRestTemplate restTemplate; + private FolioExecutionContextSetter contextSetter; + + @BeforeEach + public void beforeEach() { + contextSetter = initContext(); + } + + @AfterEach + public void afterEach() { + contextSetter.close(); + } @Test void getByIdNotFound() throws Exception { mockMvc.perform( - get(TLR_URL + UUID.randomUUID()) + get(TLR_URL + "/" + UUID.randomUUID()) .headers(defaultHeaders()) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isNotFound()); } + + @Test + public void titleLevelRequestIsCreatedForDifferentTenant() { + EcsTlr ecsTlr = buildEcsTlr(); + wireMockServer.stubFor(WireMock.post(urlMatching(".*/circulation/requests")) + .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT)) + .willReturn(jsonResponse(asJsonString(ecsTlr), HttpStatus.SC_CREATED))); + assertEquals(getCurrentTenantId(), TENANT); + + doPost(TLR_URL, ecsTlr) + .expectStatus().isCreated() + .expectBody().json(asJsonString(ecsTlr)); + + assertEquals(getCurrentTenantId(), TENANT); + wireMockServer.verify(postRequestedFor(urlMatching(".*/circulation/requests")) + .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT))); + } + + private String getCurrentTenantId() { + return context.getTenantId(); + } + + private static Map> buildDefaultHeaders() { + return new HashMap<>(defaultHeaders().entrySet() + .stream() + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))); + } + + private FolioExecutionContextSetter initContext() { + return new FolioExecutionContextSetter(moduleMetadata, buildDefaultHeaders()); + } + + private static EcsTlr buildEcsTlr() { + return new EcsTlr() + .id(randomId()) + .itemId(randomId()) + .instanceId(randomId()) + .requesterId(randomId()) + .pickupServicePointId(randomId()) + .fulfillmentPreference(EcsTlr.FulfillmentPreferenceEnum.DELIVERY) + .patronComments("random comment") + .requestExpirationDate(new Date()) + .requestType(EcsTlr.RequestTypeEnum.PAGE) + .requestLevel(EcsTlr.RequestLevelEnum.TITLE); + } + } diff --git a/src/test/java/org/folio/controller/EcsTlrControllerTest.java b/src/test/java/org/folio/controller/EcsTlrControllerTest.java index f7f5021b..47e3477f 100644 --- a/src/test/java/org/folio/controller/EcsTlrControllerTest.java +++ b/src/test/java/org/folio/controller/EcsTlrControllerTest.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.http.HttpStatus.CREATED; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import java.util.Optional; @@ -44,7 +43,7 @@ void getById() { @Test void ecsTlrShouldSuccessfullyBeCreated() { var mockRequest = new EcsTlr(); - when(requestsService.post(any(EcsTlr.class))).thenReturn(mockRequest); + when(requestsService.create(any(EcsTlr.class))).thenReturn(mockRequest); var response = requestsController.postEcsTlr(new EcsTlr()); diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index 4eaf0752..6c034c96 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -72,7 +72,7 @@ void postEcsTlr() { ecsTlr.setPickupServicePointId(pickupServicePointId.toString()); when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); - var postEcsTlr = ecsTlrService.post(ecsTlr); + var postEcsTlr = ecsTlrService.create(ecsTlr); assertEquals(id.toString(), postEcsTlr.getId()); assertEquals(instanceId.toString(), postEcsTlr.getInstanceId()); From d8ec708e1639c47db9a5fa45e1cb3241cda13a2c Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 24 Jan 2024 15:09:32 +0200 Subject: [PATCH 02/16] MODTLR-10 Add logging configuration file --- src/main/resources/log4j2.properties | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/resources/log4j2.properties diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties new file mode 100644 index 00000000..9ab6b776 --- /dev/null +++ b/src/main/resources/log4j2.properties @@ -0,0 +1,15 @@ +status = error +name = PropertiesConfig +packages = org.folio.spring.logging + +appenders = console + +appender.console.type = Console +appender.console.name = STDOUT + +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{HH:mm:ss} [$${folio:requestid:-}] [$${folio:tenantid:-}] [$${folio:userid:-}] [$${folio:moduleid:-}] %-5p %-20.20C{1} %m%n + +rootLogger.level = info +rootLogger.appenderRefs = info +rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file From e20dc4ef6b63cdeb109e122f49068fa3924fd501 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 24 Jan 2024 16:56:52 +0200 Subject: [PATCH 03/16] MODTLR-10 Add requestDate to ECS TLR schema, fix test --- .../org/folio/domain/entity/EcsTlrEntity.java | 1 + .../folio/service/impl/EcsTlrServiceImpl.java | 16 ++++++++++++---- .../db/changelog/changes/initial_schema.xml | 1 + .../resources/swagger.api/schemas/EcsTlr.yaml | 4 ++++ .../org/folio/service/EcsTlrServiceTest.java | 11 ++++++++++- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java index 77984b48..84343d04 100644 --- a/src/main/java/org/folio/domain/entity/EcsTlrEntity.java +++ b/src/main/java/org/folio/domain/entity/EcsTlrEntity.java @@ -26,6 +26,7 @@ public class EcsTlrEntity { private String requestType; private String requestLevel; private Date requestExpirationDate; + private Date requestDate; private String patronComments; private String fulfillmentPreference; private UUID pickupServicePointId; diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 058312f4..cc163c42 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -36,12 +36,20 @@ public Optional get(UUID id) { @Override public EcsTlr create(EcsTlr ecsTlr) { log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); - Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr); - Request cretedRequest = tenantScopedExecutionService.execute("dummy-tenant", // TODO: replace with real tenantId - () -> circulationClient.createTitleLevelRequest(mappedRequest)); - log.info("create:: title-level request created: {}", cretedRequest.getId()); + createRequest(ecsTlr, "dummy-tenant"); // TODO: replace with real tenantId return requestsMapper.mapEntityToDto(ecsTlrRepository.save( requestsMapper.mapDtoToEntity(ecsTlr))); } + + private Request createRequest(EcsTlr ecsTlr, String tenantId) { + log.info("createRequest:: creating request for ECS TLR {} and tenant {}", ecsTlr.getId(), tenantId); + Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr); + Request createdRequest = tenantScopedExecutionService.execute(tenantId, + () -> circulationClient.createTitleLevelRequest(mappedRequest)); + log.info("createRequest:: request created: {}", createdRequest.getId()); + log.debug("createRequest:: request={}", () -> createdRequest); + + return createdRequest; + } } diff --git a/src/main/resources/db/changelog/changes/initial_schema.xml b/src/main/resources/db/changelog/changes/initial_schema.xml index b8aa6165..d0ea0ae6 100644 --- a/src/main/resources/db/changelog/changes/initial_schema.xml +++ b/src/main/resources/db/changelog/changes/initial_schema.xml @@ -17,6 +17,7 @@ + diff --git a/src/main/resources/swagger.api/schemas/EcsTlr.yaml b/src/main/resources/swagger.api/schemas/EcsTlr.yaml index ca60b510..308a9957 100644 --- a/src/main/resources/swagger.api/schemas/EcsTlr.yaml +++ b/src/main/resources/swagger.api/schemas/EcsTlr.yaml @@ -23,6 +23,10 @@ EcsTlr: description: "Date when the request expires" type: string format: date-time + requestDate: + description: "Date when the request was placed" + type: string + format: date-time patronComments: description: "Comments made by the patron" type: string diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index 6c034c96..657e5f35 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -8,6 +8,7 @@ import java.util.UUID; 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.mapper.EcsTlrMapperImpl; @@ -28,6 +29,8 @@ class EcsTlrServiceTest { private EcsTlrServiceImpl ecsTlrService; @Mock private EcsTlrRepository ecsTlrRepository; + @Mock + private TenantScopedExecutionService tenantScopedExecutionService; @Spy private final EcsTlrMapper ecsTlrMapper = new EcsTlrMapperImpl(); @@ -46,7 +49,8 @@ void postEcsTlr() { var requestType = EcsTlr.RequestTypeEnum.PAGE; var requestLevel = EcsTlr.RequestLevelEnum.TITLE; var fulfillmentPreference = EcsTlr.FulfillmentPreferenceEnum.HOLD_SHELF; - var requestExpirationDate = DateTime.now().toDate(); + var requestExpirationDate = DateTime.now().plusDays(7).toDate(); + var requestDate = DateTime.now().toDate(); var patronComments = "Test comment"; var mockEcsTlrEntity = new EcsTlrEntity(); @@ -56,6 +60,7 @@ void postEcsTlr() { mockEcsTlrEntity.setRequestType(requestType.toString()); mockEcsTlrEntity.setRequestLevel(requestLevel.getValue()); mockEcsTlrEntity.setRequestExpirationDate(requestExpirationDate); + mockEcsTlrEntity.setRequestDate(requestDate); mockEcsTlrEntity.setPatronComments(patronComments); mockEcsTlrEntity.setFulfillmentPreference(fulfillmentPreference.getValue()); mockEcsTlrEntity.setPickupServicePointId(pickupServicePointId); @@ -67,11 +72,14 @@ void postEcsTlr() { ecsTlr.setRequestType(requestType); ecsTlr.setRequestLevel(requestLevel); ecsTlr.setRequestExpirationDate(requestExpirationDate); + ecsTlr.setRequestDate(requestDate); ecsTlr.setPatronComments(patronComments); ecsTlr.setFulfillmentPreference(fulfillmentPreference); ecsTlr.setPickupServicePointId(pickupServicePointId.toString()); when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); + when(tenantScopedExecutionService.execute(any(String.class), any())) + .thenReturn(new Request().id(UUID.randomUUID().toString())); var postEcsTlr = ecsTlrService.create(ecsTlr); assertEquals(id.toString(), postEcsTlr.getId()); @@ -79,6 +87,7 @@ void postEcsTlr() { assertEquals(requesterId.toString(), postEcsTlr.getRequesterId()); assertEquals(requestType, postEcsTlr.getRequestType()); assertEquals(requestExpirationDate, postEcsTlr.getRequestExpirationDate()); + assertEquals(requestDate, postEcsTlr.getRequestDate()); assertEquals(patronComments, postEcsTlr.getPatronComments()); assertEquals(fulfillmentPreference, postEcsTlr.getFulfillmentPreference()); assertEquals(pickupServicePointId.toString(), postEcsTlr.getPickupServicePointId()); From 762a2f1dd22e2ceeadf25c3663e7547e5cfa6ae1 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Wed, 24 Jan 2024 16:59:34 +0200 Subject: [PATCH 04/16] MODTLR-10 Replace dummy tenantId with "university" --- src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java | 2 +- src/test/java/org/folio/api/EcsTlrApiTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index cc163c42..2a64bcee 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -36,7 +36,7 @@ public Optional get(UUID id) { @Override public EcsTlr create(EcsTlr ecsTlr) { log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); - createRequest(ecsTlr, "dummy-tenant"); // TODO: replace with real tenantId + createRequest(ecsTlr, "university"); // TODO: replace with real tenantId return requestsMapper.mapEntityToDto(ecsTlrRepository.save( requestsMapper.mapDtoToEntity(ecsTlr))); diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index c24dad22..ca11c335 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -31,7 +31,7 @@ class EcsTlrApiTest extends BaseIT { private static final String TLR_URL = "/tlr/ecs-tlr"; - private static final String ANOTHER_TENANT = "dummy-tenant"; + private static final String ANOTHER_TENANT = "university"; private static final String TENANT_HEADER = "x-okapi-tenant"; @Autowired From bb74f551cff7407fd76c1b9d984995e6ac497b38 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 25 Jan 2024 15:37:51 +0200 Subject: [PATCH 05/16] MODTLR-10 Revert cosmetic changes --- .../java/org/folio/client/CirculationClient.java | 2 +- .../java/org/folio/controller/EcsTlrController.java | 2 +- .../java/org/folio/domain/mapper/EcsTlrMapper.java | 12 ++++++------ src/main/java/org/folio/service/EcsTlrService.java | 2 +- .../org/folio/service/impl/EcsTlrServiceImpl.java | 4 ++-- .../org/folio/controller/EcsTlrControllerTest.java | 2 +- .../java/org/folio/service/EcsTlrServiceTest.java | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/folio/client/CirculationClient.java b/src/main/java/org/folio/client/CirculationClient.java index 043dc9df..2c0cb4bc 100644 --- a/src/main/java/org/folio/client/CirculationClient.java +++ b/src/main/java/org/folio/client/CirculationClient.java @@ -9,5 +9,5 @@ public interface CirculationClient { @PostMapping("/circulation/requests") - Request createTitleLevelRequest(Request request); + Request createRequest(Request request); } diff --git a/src/main/java/org/folio/controller/EcsTlrController.java b/src/main/java/org/folio/controller/EcsTlrController.java index 7f461ce5..9fe5e947 100644 --- a/src/main/java/org/folio/controller/EcsTlrController.java +++ b/src/main/java/org/folio/controller/EcsTlrController.java @@ -34,6 +34,6 @@ public ResponseEntity getEcsTlrById(UUID requestId) { public ResponseEntity postEcsTlr(EcsTlr ecsTlr) { log.debug("postEcsTlr:: parameters ecsTlr: {}", ecsTlr); - return ResponseEntity.status(CREATED).body(ecsTlrService.create(ecsTlr)); + return ResponseEntity.status(CREATED).body(ecsTlrService.post(ecsTlr)); } } diff --git a/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java b/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java index cb06de46..96285bb6 100644 --- a/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java +++ b/src/main/java/org/folio/domain/mapper/EcsTlrMapper.java @@ -37,18 +37,18 @@ default EcsTlr.FulfillmentPreferenceEnum mapFulfillmentPreference(String fulfill } @Named("RequestTypeToString") - default String mapRequestType(EcsTlr.RequestTypeEnum requestType) { - return requestType != null ? requestType.getValue() : null; + default String mapRequestTypeToString(EcsTlr.RequestTypeEnum requestTypeEnum) { + return requestTypeEnum != null ? requestTypeEnum.getValue() : null; } @Named("RequestLevelToString") - default String mapRequestLevel(EcsTlr.RequestLevelEnum requestLevel) { - return requestLevel != null ? requestLevel.getValue() : null; + default String mapRequestLevelToString(EcsTlr.RequestLevelEnum requestLevelEnum) { + return requestLevelEnum != null ? requestLevelEnum.getValue() : null; } @Named("FulfillmentPreferenceToString") - default String mapFulfillmentPreference(EcsTlr.FulfillmentPreferenceEnum fulfillmentPreference) { - return fulfillmentPreference != null ? fulfillmentPreference.getValue() : null; + default String mapFulfillmentPreferenceToString(EcsTlr.FulfillmentPreferenceEnum fulfillmentPreferenceEnum) { + return fulfillmentPreferenceEnum != null ? fulfillmentPreferenceEnum.getValue() : null; } Request mapDtoToRequest(EcsTlr ecsTlr); diff --git a/src/main/java/org/folio/service/EcsTlrService.java b/src/main/java/org/folio/service/EcsTlrService.java index bbee5bb8..4d7da52a 100644 --- a/src/main/java/org/folio/service/EcsTlrService.java +++ b/src/main/java/org/folio/service/EcsTlrService.java @@ -7,5 +7,5 @@ public interface EcsTlrService { Optional get(UUID requestId); - EcsTlr create(EcsTlr ecsTlr); + EcsTlr post(EcsTlr ecsTlr); } diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 2a64bcee..c7c2c162 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -34,7 +34,7 @@ public Optional get(UUID id) { } @Override - public EcsTlr create(EcsTlr ecsTlr) { + public EcsTlr post(EcsTlr ecsTlr) { log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); createRequest(ecsTlr, "university"); // TODO: replace with real tenantId @@ -46,7 +46,7 @@ private Request createRequest(EcsTlr ecsTlr, String tenantId) { log.info("createRequest:: creating request for ECS TLR {} and tenant {}", ecsTlr.getId(), tenantId); Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr); Request createdRequest = tenantScopedExecutionService.execute(tenantId, - () -> circulationClient.createTitleLevelRequest(mappedRequest)); + () -> circulationClient.createRequest(mappedRequest)); log.info("createRequest:: request created: {}", createdRequest.getId()); log.debug("createRequest:: request={}", () -> createdRequest); diff --git a/src/test/java/org/folio/controller/EcsTlrControllerTest.java b/src/test/java/org/folio/controller/EcsTlrControllerTest.java index 47e3477f..5d99b86e 100644 --- a/src/test/java/org/folio/controller/EcsTlrControllerTest.java +++ b/src/test/java/org/folio/controller/EcsTlrControllerTest.java @@ -43,7 +43,7 @@ void getById() { @Test void ecsTlrShouldSuccessfullyBeCreated() { var mockRequest = new EcsTlr(); - when(requestsService.create(any(EcsTlr.class))).thenReturn(mockRequest); + when(requestsService.post(any(EcsTlr.class))).thenReturn(mockRequest); var response = requestsController.postEcsTlr(new EcsTlr()); diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index 657e5f35..f2904003 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -80,7 +80,7 @@ void postEcsTlr() { when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); when(tenantScopedExecutionService.execute(any(String.class), any())) .thenReturn(new Request().id(UUID.randomUUID().toString())); - var postEcsTlr = ecsTlrService.create(ecsTlr); + var postEcsTlr = ecsTlrService.post(ecsTlr); assertEquals(id.toString(), postEcsTlr.getId()); assertEquals(instanceId.toString(), postEcsTlr.getInstanceId()); From 0466b9febf0b33c5fbfa53c780f6727ea46b3eed Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 25 Jan 2024 15:41:55 +0200 Subject: [PATCH 06/16] MODTLR-10 Attempt to fix Kafka listener test: increase timeout --- src/test/java/org/folio/controller/KafkaEventListenerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/folio/controller/KafkaEventListenerTest.java b/src/test/java/org/folio/controller/KafkaEventListenerTest.java index a1df4c60..88184f33 100644 --- a/src/test/java/org/folio/controller/KafkaEventListenerTest.java +++ b/src/test/java/org/folio/controller/KafkaEventListenerTest.java @@ -93,7 +93,7 @@ private static void publishEvent(String topic, String payload) { private static void waitForOffset(String topic, String consumerGroupId, int expectedOffset) { Awaitility.await() - .atMost(30, TimeUnit.SECONDS) + .atMost(60, TimeUnit.SECONDS) .until(() -> getOffset(topic, consumerGroupId), offset -> offset.equals(expectedOffset)); } From 8ceecac2fa0c07609b262e0ea3b3c6f9c0247b5b Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Thu, 25 Jan 2024 16:16:31 +0200 Subject: [PATCH 07/16] MODTLR-10 Fix code smells --- .../exception/TenantScopedExecutionException.java | 10 ++++++++++ .../service/impl/TenantScopedExecutionServiceImpl.java | 3 ++- src/test/java/org/folio/api/EcsTlrApiTest.java | 6 +++--- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/folio/exception/TenantScopedExecutionException.java diff --git a/src/main/java/org/folio/exception/TenantScopedExecutionException.java b/src/main/java/org/folio/exception/TenantScopedExecutionException.java new file mode 100644 index 00000000..14a3f431 --- /dev/null +++ b/src/main/java/org/folio/exception/TenantScopedExecutionException.java @@ -0,0 +1,10 @@ +package org.folio.exception; + +public class TenantScopedExecutionException extends RuntimeException { + private final String tenantId; + + public TenantScopedExecutionException(Exception cause, String tenantId) { + super(cause); + this.tenantId = tenantId; + } +} diff --git a/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java index 4248458b..7742b4d0 100644 --- a/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java +++ b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.concurrent.Callable; +import org.folio.exception.TenantScopedExecutionException; import org.folio.service.TenantScopedExecutionService; import org.folio.spring.FolioExecutionContext; import org.folio.spring.FolioModuleMetadata; @@ -33,7 +34,7 @@ public T execute(String tenantId, Callable action) { return action.call(); } catch (Exception e) { log.error("execute:: tenantId={}", tenantId, e); - throw new RuntimeException(e); + throw new TenantScopedExecutionException(e, tenantId); } } } diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index ca11c335..094744e7 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -62,18 +62,18 @@ void getByIdNotFound() throws Exception { } @Test - public void titleLevelRequestIsCreatedForDifferentTenant() { + void titleLevelRequestIsCreatedForDifferentTenant() { EcsTlr ecsTlr = buildEcsTlr(); wireMockServer.stubFor(WireMock.post(urlMatching(".*/circulation/requests")) .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT)) .willReturn(jsonResponse(asJsonString(ecsTlr), HttpStatus.SC_CREATED))); - assertEquals(getCurrentTenantId(), TENANT); + assertEquals(TENANT, getCurrentTenantId()); doPost(TLR_URL, ecsTlr) .expectStatus().isCreated() .expectBody().json(asJsonString(ecsTlr)); - assertEquals(getCurrentTenantId(), TENANT); + assertEquals(TENANT, getCurrentTenantId()); wireMockServer.verify(postRequestedFor(urlMatching(".*/circulation/requests")) .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT))); } From 65b3afae76bbd263ef75f7869f543412e140629f Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 12:59:13 +0200 Subject: [PATCH 08/16] MODTLR-10 Test for TenantScopedExecutionService --- .../TenantScopedExecutionException.java | 3 ++ .../TenantScopedExecutionServiceTest.java | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java diff --git a/src/main/java/org/folio/exception/TenantScopedExecutionException.java b/src/main/java/org/folio/exception/TenantScopedExecutionException.java index 14a3f431..dec59750 100644 --- a/src/main/java/org/folio/exception/TenantScopedExecutionException.java +++ b/src/main/java/org/folio/exception/TenantScopedExecutionException.java @@ -1,5 +1,8 @@ package org.folio.exception; +import lombok.Getter; + +@Getter public class TenantScopedExecutionException extends RuntimeException { private final String tenantId; diff --git a/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java b/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java new file mode 100644 index 00000000..20d8bee2 --- /dev/null +++ b/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java @@ -0,0 +1,50 @@ +package org.folio.service; + +import static java.util.Collections.emptyMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.folio.exception.TenantScopedExecutionException; +import org.folio.service.impl.TenantScopedExecutionServiceImpl; +import org.folio.spring.FolioExecutionContext; +import org.folio.spring.FolioModuleMetadata; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class TenantScopedExecutionServiceTest { + + @Mock + private FolioExecutionContext folioExecutionContext; + @InjectMocks + private TenantScopedExecutionServiceImpl executionService; + + @Test + void executionExceptionIsForwarded() { + when(folioExecutionContext.getAllHeaders()).thenReturn(new HashMap<>()); + String tenantId = "test-tenant"; + String errorMessage = "cause message"; + + TenantScopedExecutionException exception = assertThrows(TenantScopedExecutionException.class, + () -> executionService.execute(tenantId, () -> { + throw new IllegalAccessException(errorMessage); + })); + + assertEquals(tenantId, exception.getTenantId()); + assertNotNull(exception.getCause()); + assertInstanceOf(IllegalAccessException.class, exception.getCause()); + assertEquals(errorMessage, exception.getCause().getMessage()); + } +} \ No newline at end of file From 7bed59c137af03f2275ad6bdf68b9c2a539ab343 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 13:09:01 +0200 Subject: [PATCH 09/16] MODTLR-10 Remove unused imports --- .../org/folio/service/TenantScopedExecutionServiceTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java b/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java index 20d8bee2..937d3114 100644 --- a/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java +++ b/src/test/java/org/folio/service/TenantScopedExecutionServiceTest.java @@ -1,26 +1,20 @@ package org.folio.service; -import static java.util.Collections.emptyMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.when; -import java.util.Collections; import java.util.HashMap; -import java.util.Map; import org.folio.exception.TenantScopedExecutionException; import org.folio.service.impl.TenantScopedExecutionServiceImpl; import org.folio.spring.FolioExecutionContext; -import org.folio.spring.FolioModuleMetadata; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) From 5e64f4b3cad7735ed809c164f6c7449cbdcf5dd7 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 13:11:24 +0200 Subject: [PATCH 10/16] MODTLR-10 Add Kafka environment variables --- descriptors/ModuleDescriptor-template.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index fb89305c..0bd07204 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -73,9 +73,18 @@ } }, "env": [ - { "name": "JAVA_OPTIONS", + { + "name": "JAVA_OPTIONS", "value": "-XX:MaxRAMPercentage=66.0" }, + { + "name": "KAFKA_HOST", + "value": "kafka" + }, + { + "name": "KAFKA_PORT", + "value": "9092" + }, { "name": "DB_HOST", "value": "postgres" }, { "name": "DB_PORT", "value": "5432" }, { "name": "DB_USERNAME", "value": "folio_admin" }, From 2da1600746eb1a9424f2c94c161c76d7631ca6ad Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 13:17:11 +0200 Subject: [PATCH 11/16] MODTLR-10 Add env variable OKAPI_URL --- descriptors/ModuleDescriptor-template.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index 0bd07204..94d6d14e 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -77,6 +77,10 @@ "name": "JAVA_OPTIONS", "value": "-XX:MaxRAMPercentage=66.0" }, + { + "name": "OKAPI_URL", + "value": "http://okapi:9130" + }, { "name": "KAFKA_HOST", "value": "kafka" From d625dab8a9ec4a33db35a3b156e1f87aaf4eaa7e Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 13:33:12 +0200 Subject: [PATCH 12/16] MODTLR-10 Extend EcsTlrApiTest --- src/test/java/org/folio/api/EcsTlrApiTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/folio/api/EcsTlrApiTest.java b/src/test/java/org/folio/api/EcsTlrApiTest.java index 094744e7..0aa3fecc 100644 --- a/src/test/java/org/folio/api/EcsTlrApiTest.java +++ b/src/test/java/org/folio/api/EcsTlrApiTest.java @@ -19,6 +19,7 @@ import java.util.UUID; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.jsonResponse; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; @@ -64,18 +65,20 @@ void getByIdNotFound() throws Exception { @Test void titleLevelRequestIsCreatedForDifferentTenant() { EcsTlr ecsTlr = buildEcsTlr(); + String ecsTlrJson = asJsonString(ecsTlr); wireMockServer.stubFor(WireMock.post(urlMatching(".*/circulation/requests")) .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT)) - .willReturn(jsonResponse(asJsonString(ecsTlr), HttpStatus.SC_CREATED))); + .willReturn(jsonResponse(ecsTlrJson, HttpStatus.SC_CREATED))); assertEquals(TENANT, getCurrentTenantId()); doPost(TLR_URL, ecsTlr) .expectStatus().isCreated() - .expectBody().json(asJsonString(ecsTlr)); + .expectBody().json(ecsTlrJson); assertEquals(TENANT, getCurrentTenantId()); wireMockServer.verify(postRequestedFor(urlMatching(".*/circulation/requests")) - .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT))); + .withHeader(TENANT_HEADER, equalTo(ANOTHER_TENANT)) + .withRequestBody(equalToJson(ecsTlrJson))); } private String getCurrentTenantId() { From 7377190ab6df00b17c4947c07b29254fc10bb67e Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 13:33:27 +0200 Subject: [PATCH 13/16] MODTLR-10 Minor adjustments --- src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java | 2 +- src/test/java/org/folio/api/BaseIT.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index c7c2c162..33a43ec1 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -35,7 +35,7 @@ public Optional get(UUID id) { @Override public EcsTlr post(EcsTlr ecsTlr) { - log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); + log.debug("post:: parameters ecsTlr: {}", () -> ecsTlr); createRequest(ecsTlr, "university"); // TODO: replace with real tenantId return requestsMapper.mapEntityToDto(ecsTlrRepository.save( diff --git a/src/test/java/org/folio/api/BaseIT.java b/src/test/java/org/folio/api/BaseIT.java index c324081c..73e1103a 100644 --- a/src/test/java/org/folio/api/BaseIT.java +++ b/src/test/java/org/folio/api/BaseIT.java @@ -128,11 +128,11 @@ protected WebTestClient.RequestBodySpec buildRequest(HttpMethod method, String u .header(XOkapiHeaders.TENANT, TENANT) .header(XOkapiHeaders.URL, wireMockServer.baseUrl()) .header(XOkapiHeaders.TOKEN, TOKEN) - .header(XOkapiHeaders.USER_ID, UUID.randomUUID().toString()); + .header(XOkapiHeaders.USER_ID, randomId()); } - protected WebTestClient.ResponseSpec doPost(String uri, Object payload) { - return buildRequest(HttpMethod.POST, uri) + protected WebTestClient.ResponseSpec doPost(String url, Object payload) { + return buildRequest(HttpMethod.POST, url) .body(BodyInserters.fromValue(payload)) .exchange(); } From 268058319327d73cdd4c8c3eea07dc1fef477248 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 17:11:44 +0200 Subject: [PATCH 14/16] MODTLR-10 Rename method --- .../java/org/folio/service/impl/EcsTlrServiceImpl.java | 10 +++++----- src/main/resources/log4j2.properties | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 33a43ec1..db29553e 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -36,19 +36,19 @@ public Optional get(UUID id) { @Override public EcsTlr post(EcsTlr ecsTlr) { log.debug("post:: parameters ecsTlr: {}", () -> ecsTlr); - createRequest(ecsTlr, "university"); // TODO: replace with real tenantId + createRemoteRequest(ecsTlr, "university"); // TODO: replace with real tenantId return requestsMapper.mapEntityToDto(ecsTlrRepository.save( requestsMapper.mapDtoToEntity(ecsTlr))); } - private Request createRequest(EcsTlr ecsTlr, String tenantId) { - log.info("createRequest:: creating request for ECS TLR {} and tenant {}", ecsTlr.getId(), tenantId); + private Request createRemoteRequest(EcsTlr ecsTlr, String tenantId) { + log.info("createRemoteRequest:: creating remote request for ECS TLR {} and tenant {}", ecsTlr.getId(), tenantId); Request mappedRequest = requestsMapper.mapDtoToRequest(ecsTlr); Request createdRequest = tenantScopedExecutionService.execute(tenantId, () -> circulationClient.createRequest(mappedRequest)); - log.info("createRequest:: request created: {}", createdRequest.getId()); - log.debug("createRequest:: request={}", () -> createdRequest); + log.info("createRemoteRequest:: request created: {}", createdRequest.getId()); + log.debug("createRemoteRequest:: request={}", () -> createdRequest); return createdRequest; } diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties index 9ab6b776..6fbbd253 100644 --- a/src/main/resources/log4j2.properties +++ b/src/main/resources/log4j2.properties @@ -10,6 +10,6 @@ appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{HH:mm:ss} [$${folio:requestid:-}] [$${folio:tenantid:-}] [$${folio:userid:-}] [$${folio:moduleid:-}] %-5p %-20.20C{1} %m%n -rootLogger.level = info -rootLogger.appenderRefs = info +rootLogger.level = debug +rootLogger.appenderRefs = debug rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file From 302a0584ca3541788c1e8f3d16259f14519e5af0 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 18:58:39 +0200 Subject: [PATCH 15/16] MODTLR-10 Replace "=" with ":" in logs --- src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java | 2 +- .../folio/service/impl/TenantScopedExecutionServiceImpl.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index db29553e..7456516d 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -48,7 +48,7 @@ private Request createRemoteRequest(EcsTlr ecsTlr, String tenantId) { Request createdRequest = tenantScopedExecutionService.execute(tenantId, () -> circulationClient.createRequest(mappedRequest)); log.info("createRemoteRequest:: request created: {}", createdRequest.getId()); - log.debug("createRemoteRequest:: request={}", () -> createdRequest); + log.debug("createRemoteRequest:: request: {}", () -> createdRequest); return createdRequest; } diff --git a/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java index 7742b4d0..5d871d98 100644 --- a/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java +++ b/src/main/java/org/folio/service/impl/TenantScopedExecutionServiceImpl.java @@ -26,14 +26,14 @@ public class TenantScopedExecutionServiceImpl implements TenantScopedExecutionSe @Override public T execute(String tenantId, Callable action) { - log.info("execute:: tenantId={}", tenantId); + log.info("execute:: tenantId: {}", tenantId); Map> headers = executionContext.getAllHeaders(); headers.put(XOkapiHeaders.TENANT, List.of(tenantId)); try (var x = new FolioExecutionContextSetter(moduleMetadata, headers)) { return action.call(); } catch (Exception e) { - log.error("execute:: tenantId={}", tenantId, e); + log.error("execute:: tenantId: {}", tenantId, e); throw new TenantScopedExecutionException(e, tenantId); } } From c465c50e4d2dba9d62a4e24b73f984432c4c76e3 Mon Sep 17 00:00:00 2001 From: Oleksandr Vidinieiev Date: Fri, 26 Jan 2024 18:58:53 +0200 Subject: [PATCH 16/16] MODTLR-10 Make requestDate required --- src/main/resources/swagger.api/schemas/EcsTlr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/swagger.api/schemas/EcsTlr.yaml b/src/main/resources/swagger.api/schemas/EcsTlr.yaml index 308a9957..3405bf5e 100644 --- a/src/main/resources/swagger.api/schemas/EcsTlr.yaml +++ b/src/main/resources/swagger.api/schemas/EcsTlr.yaml @@ -46,3 +46,4 @@ EcsTlr: - requestType - requestLevel - fulfillmentPreference + - requestDate