Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
## XXXX-XX-XX v3.11.0-SNAPSHOT
## XXXX-XX-XX v4.0.0-SNAPSHOT
* [MODSOURMAN-1304](https://folio-org.atlassian.net/browse/MODSOURMAN-1304) Handle journal records for MARC on Instance errors and COMPLETED INSTANCE/MARC_BIB events
* [MODSOURMAN-1323](https://folio-org.atlassian.net/browse/MODSOURMAN-1323) Ensure holdings validation to check central ECS tenant
* [MODDATAIMP-1214](https://folio-org.atlassian.net/browse/MODDATAIMP-1214) Ensure permission that allows update of shared instance and MARC
* [MODSOURMAN-1136](https://folio-org.atlassian.net/browse/MODSOURMAN-1136) Send Kafka event when JobExecution is cancelled
* [MODSOURMAN-1353](https://folio-org.atlassian.net/browse/MODSOURMAN-1353) Remove GET /change-manager/parsedRecords endpoint

## 2025-03-13 v3.10.0
* [MODSOURMAN-1246](https://folio-org.atlassian.net/browse/MODSOURMAN-1246) Added data import completion notifications
Expand Down
14 changes: 1 addition & 13 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,20 +397,8 @@
},
{
"id": "source-manager-parsed-records",
"version": "3.0",
"version": "4.0",
"handlers": [
{
"methods": [
"GET"
],
"pathPattern": "/change-manager/parsedRecords",
"permissionsRequired": [
"change-manager.parsedrecords.get"
],
"modulePermissions": [
"source-storage.source-records.item.get"
]
},
{
"methods": [
"PUT"
Expand Down
2 changes: 1 addition & 1 deletion mod-source-record-manager-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.folio</groupId>
<artifactId>mod-source-record-manager</artifactId>
<version>3.11.0-SNAPSHOT</version>
<version>4.0.0-SNAPSHOT</version>
</parent>

<properties>
Expand Down
2 changes: 1 addition & 1 deletion mod-source-record-manager-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.folio</groupId>
<artifactId>mod-source-record-manager</artifactId>
<version>3.11.0-SNAPSHOT</version>
<version>4.0.0-SNAPSHOT</version>
</parent>

<properties>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -241,24 +241,6 @@ public void deleteChangeManagerJobExecutionsRecordsById(String id, Map<String, S
});
}

@Override
public void getChangeManagerParsedRecords(String externalId, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
vertxContext.runOnContext(v -> {
try {
LOGGER.debug("getChangeManagerParsedRecords:: externalId {}", externalId);
parsedRecordService.getRecordByExternalId(externalId, new OkapiConnectionParams(okapiHeaders, vertxContext.owner()))
.map(GetChangeManagerParsedRecordsResponse::respond200WithApplicationJson)
.map(Response.class::cast)
.otherwise(ExceptionHelper::mapExceptionToResponse)
.onComplete(asyncResultHandler);
} catch (Exception e) {
LOGGER.warn(getMessage("getChangeManagerParsedRecords:: Failed to retrieve parsed record by externalId {}", e, externalId));
asyncResultHandler.handle(Future.succeededFuture(ExceptionHelper.mapExceptionToResponse(e)));
}
});
}

@Override
public void putChangeManagerParsedRecordsById(String id, ParsedRecordDto entity, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,6 @@
*/
public interface ParsedRecordService {

/**
* Get {@link ParsedRecordDto} by externalId
*
* @param externalId - externalId
* @param params - OkapiConnectionParams
* @return future with ParsedRecordDto, which was mapped from SourceRecord from SRS
*/
Future<ParsedRecordDto> getRecordByExternalId(String externalId, OkapiConnectionParams params);

/**
* Creates new Record in SRS with higher generation, updates status of the OLD Record and sends event with updated Record
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,46 @@
import static io.vertx.core.Future.failedFuture;
import static java.lang.String.format;

import static org.folio.HttpStatus.HTTP_NOT_FOUND;
import static org.folio.HttpStatus.HTTP_OK;
import static org.folio.verticle.consumers.util.QMEventTypes.QM_RECORD_UPDATED;

import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import javax.ws.rs.NotFoundException;

import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import org.folio.dataimport.util.OkapiConnectionParams;
import org.folio.dataimport.util.Try;
import org.folio.kafka.KafkaHeaderUtils;
import org.folio.processing.mapping.defaultmapper.processor.parameters.MappingParameters;
import org.folio.rest.client.SourceStorageSourceRecordsClient;
import org.folio.rest.jaxrs.model.ParsedRecordDto;
import org.folio.rest.jaxrs.model.SourceRecord;
import org.folio.rest.jaxrs.model.SourceRecordState;
import org.folio.services.entity.MappingRuleCacheKey;
import org.folio.services.mappers.processor.MappingParametersProvider;

@Log4j2
@Service
public class ParsedRecordServiceImpl implements ParsedRecordService {
private static final Logger LOGGER = LogManager.getLogger();
private static final AtomicInteger indexer = new AtomicInteger();

private final MappingParametersProvider mappingParametersProvider;
private final MappingRuleCache mappingRuleCache;
private final SourceRecordStateService sourceRecordStateService;
private final QuickMarcEventProducerService producerService;

@Value("${srm.kafka.QuickMarcUpdateKafkaHandler.maxDistributionNum:100}")
private int maxDistributionNum;

public ParsedRecordServiceImpl(MappingParametersProvider mappingParametersProvider,
MappingRuleCache mappingRuleCache,
SourceRecordStateService sourceRecordStateService, QuickMarcEventProducerService producerService) {
QuickMarcEventProducerService producerService) {
this.mappingParametersProvider = mappingParametersProvider;
this.mappingRuleCache = mappingRuleCache;
this.sourceRecordStateService = sourceRecordStateService;
this.producerService = producerService;
}

@Override
public Future<ParsedRecordDto> getRecordByExternalId(String externalId, OkapiConnectionParams params) {
LOGGER.debug("getRecordByExternalId:: externalId {}", externalId);
Promise<ParsedRecordDto> promise = Promise.promise();
var client = new SourceStorageSourceRecordsClient(params.getOkapiUrl(), params.getTenantId(), params.getToken());
try {
client.getSourceStorageSourceRecordsById(externalId, "EXTERNAL", null, response -> {
if (HTTP_OK.toInt() == response.result().statusCode()) {
Buffer bodyAsBuffer = response.result().bodyAsBuffer();
Try.itGet(() -> mapSourceRecordToParsedRecordDto(bodyAsBuffer))
.compose(parsedRecordDto -> sourceRecordStateService.get(parsedRecordDto.getId(), params.getTenantId())
.map(sourceRecordStateOptional -> sourceRecordStateOptional
.orElse(new SourceRecordState().withRecordState(SourceRecordState.RecordState.ACTUAL)))
.compose(sourceRecordState -> Future.succeededFuture(parsedRecordDto
.withRecordState(ParsedRecordDto.RecordState.valueOf(sourceRecordState.getRecordState().name())))))
.onComplete(parsedRecordDtoAsyncResult -> {
if (parsedRecordDtoAsyncResult.succeeded()) {
promise.complete(parsedRecordDtoAsyncResult.result());
} else {
promise.fail(parsedRecordDtoAsyncResult.cause());
}
});
} else {
String message = format("Error retrieving Record by externalId: '%s', response code %s, %s",
externalId, response.result().statusCode(), response.result().statusMessage());
if (HTTP_NOT_FOUND.toInt() == response.result().statusCode()) {
promise.fail(new NotFoundException(message));
} else {
promise.fail(message);
}
}
});
} catch (Exception e) {
log.warn("getRecordByExternalId:: Failed to GET Record from SRS", e);
promise.fail(e);
}
return promise.future();
}

@Override
public Future<Boolean> updateRecord(ParsedRecordDto parsedRecordDto, OkapiConnectionParams params) {
String snapshotId = UUID.randomUUID().toString();
Expand All @@ -117,27 +64,11 @@ public Future<Boolean> updateRecord(ParsedRecordDto parsedRecordDto, OkapiConnec
private Future<Boolean> updateRecord(ParsedRecordDto parsedRecordDto, String snapshotId,
MappingParameters mappingParameters, JsonObject mappingRules,
OkapiConnectionParams params) {
var sourceRecordState = new SourceRecordState()
.withRecordState(SourceRecordState.RecordState.IN_PROGRESS)
.withSourceRecordId(parsedRecordDto.getId());
var tenantId = params.getTenantId();
var key = String.valueOf(indexer.incrementAndGet() % maxDistributionNum);
var kafkaHeaders = KafkaHeaderUtils.kafkaHeadersFromMultiMap(params.getHeaders());
var eventPayload = prepareEventPayload(parsedRecordDto, mappingRules, mappingParameters, snapshotId);
return sourceRecordStateService.save(sourceRecordState, tenantId)
.compose(s -> producerService.sendEventWithZipping(eventPayload, QM_RECORD_UPDATED.name(), key, tenantId, kafkaHeaders));
}

private ParsedRecordDto mapSourceRecordToParsedRecordDto(Buffer body) {
SourceRecord sourceRecord = body.toJsonObject().mapTo(SourceRecord.class);
return new ParsedRecordDto()
.withId(sourceRecord.getRecordId())
.withParsedRecord(sourceRecord.getParsedRecord())
.withRecordType(ParsedRecordDto.RecordType.fromValue(sourceRecord.getRecordType().value()))
.withExternalIdsHolder(sourceRecord.getExternalIdsHolder())
.withAdditionalInfo(sourceRecord.getAdditionalInfo())
.withMetadata(sourceRecord.getMetadata())
.withRecordState(ParsedRecordDto.RecordState.ACTUAL);
return producerService.sendEventWithZipping(eventPayload, QM_RECORD_UPDATED.name(), key, tenantId, kafkaHeaders);
}

private String prepareEventPayload(ParsedRecordDto parsedRecordDto, JsonObject mappingRules,
Expand Down
Loading