Search in sources :

Example 1 with OptimisticLockingException

use of org.folio.inventory.dataimport.exceptions.OptimisticLockingException in project mod-inventory by folio-org.

the class HoldingsUpdateDelegate method updateHoldingsRecord.

private Future<HoldingsRecord> updateHoldingsRecord(HoldingsRecord holdingsRecord, HoldingsRecordCollection holdingsRecordCollection) {
    Promise<HoldingsRecord> promise = Promise.promise();
    holdingsRecordCollection.update(holdingsRecord, success -> promise.complete(holdingsRecord), failure -> {
        if (failure.getStatusCode() == HttpStatus.SC_CONFLICT) {
            promise.fail(new OptimisticLockingException(failure.getReason()));
        } else {
            LOGGER.error(format("Error updating Holdings - %s, status code %s", failure.getReason(), failure.getStatusCode()));
            promise.fail(failure.getReason());
        }
    });
    return promise.future();
}
Also used : HoldingsRecord(org.folio.HoldingsRecord) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException)

Example 2 with OptimisticLockingException

use of org.folio.inventory.dataimport.exceptions.OptimisticLockingException in project mod-inventory by folio-org.

the class InstanceUpdateDelegate method updateInstanceInStorage.

private Future<Instance> updateInstanceInStorage(Instance instance, InstanceCollection instanceCollection) {
    Promise<Instance> promise = Promise.promise();
    instanceCollection.update(instance, success -> promise.complete(instance), failure -> {
        if (failure.getStatusCode() == HttpStatus.SC_CONFLICT) {
            promise.fail(new OptimisticLockingException(failure.getReason()));
        } else {
            LOGGER.error(format("Error updating Instance - %s, status code %s", failure.getReason(), failure.getStatusCode()));
            promise.fail(failure.getReason());
        }
    });
    return promise.future();
}
Also used : Instance(org.folio.inventory.domain.instances.Instance) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException)

Example 3 with OptimisticLockingException

use of org.folio.inventory.dataimport.exceptions.OptimisticLockingException in project mod-inventory by folio-org.

the class MarcBibModifiedPostProcessingEventHandler method handle.

@Override
public CompletableFuture<DataImportEventPayload> handle(DataImportEventPayload dataImportEventPayload) {
    CompletableFuture<DataImportEventPayload> future = new CompletableFuture<>();
    try {
        HashMap<String, String> payloadContext = dataImportEventPayload.getContext();
        if (isNull(payloadContext) || isBlank(payloadContext.get(MARC_BIBLIOGRAPHIC.value()))) {
            LOGGER.error(PAYLOAD_HAS_NO_DATA_MSG);
            return CompletableFuture.failedFuture(new EventProcessingException(PAYLOAD_HAS_NO_DATA_MSG));
        }
        LOGGER.info("Processing ReplaceInstanceEventHandler starting with jobExecutionId: {}.", dataImportEventPayload.getJobExecutionId());
        Record record = new JsonObject(payloadContext.get(MARC_BIBLIOGRAPHIC.value())).mapTo(Record.class);
        String instanceId = ParsedRecordUtil.getAdditionalSubfieldValue(record.getParsedRecord(), ParsedRecordUtil.AdditionalSubfields.I);
        if (isBlank(instanceId)) {
            return CompletableFuture.completedFuture(dataImportEventPayload);
        }
        record.setExternalIdsHolder(new ExternalIdsHolder().withInstanceId(instanceId));
        Context context = EventHandlingUtil.constructContext(dataImportEventPayload.getTenant(), dataImportEventPayload.getToken(), dataImportEventPayload.getOkapiUrl());
        Promise<Instance> instanceUpdatePromise = Promise.promise();
        mappingMetadataCache.get(dataImportEventPayload.getJobExecutionId(), context).map(parametersOptional -> parametersOptional.orElseThrow(() -> new EventProcessingException(format(MAPPING_METADATA_NOT_FOUND_MSG, dataImportEventPayload.getJobExecutionId())))).map(mappingMetadataDto -> buildPayloadForInstanceUpdate(dataImportEventPayload, mappingMetadataDto)).compose(payloadForUpdate -> instanceUpdateDelegate.handle(payloadForUpdate, record, context)).onSuccess(instanceUpdatePromise::complete).compose(updatedInstance -> precedingSucceedingTitlesHelper.getExistingPrecedingSucceedingTitles(updatedInstance, context)).map(precedingSucceedingTitles -> precedingSucceedingTitles.stream().map(titleJson -> titleJson.getString("id")).collect(Collectors.toSet())).compose(precedingSucceedingTitles -> precedingSucceedingTitlesHelper.deletePrecedingSucceedingTitles(precedingSucceedingTitles, context)).compose(ar -> precedingSucceedingTitlesHelper.createPrecedingSucceedingTitles(instanceUpdatePromise.future().result(), context)).onComplete(updateAr -> {
            if (updateAr.succeeded()) {
                dataImportEventPayload.getContext().remove(CURRENT_RETRY_NUMBER);
                Instance resultedInstance = instanceUpdatePromise.future().result();
                if (resultedInstance.getVersion() != null) {
                    int currentVersion = Integer.parseInt(resultedInstance.getVersion());
                    int incrementedVersion = currentVersion + 1;
                    resultedInstance.setVersion(String.valueOf(incrementedVersion));
                }
                dataImportEventPayload.getContext().put(INSTANCE.value(), Json.encode(resultedInstance));
                future.complete(dataImportEventPayload);
            } else {
                if (updateAr.cause() instanceof OptimisticLockingException) {
                    processOLError(dataImportEventPayload, future, updateAr);
                } else {
                    dataImportEventPayload.getContext().remove(CURRENT_RETRY_NUMBER);
                    LOGGER.error("Error updating inventory instance by id: '{}' by jobExecutionId: '{}'", instanceId, dataImportEventPayload.getJobExecutionId(), updateAr.cause());
                    future.completeExceptionally(updateAr.cause());
                }
            }
        });
    } catch (Exception e) {
        dataImportEventPayload.getContext().remove(CURRENT_RETRY_NUMBER);
        LOGGER.error("Error updating inventory instance", e);
        future.completeExceptionally(e);
    }
    return future;
}
Also used : Context(org.folio.inventory.common.Context) ParsedRecordUtil(org.folio.inventory.dataimport.util.ParsedRecordUtil) Json(io.vertx.core.json.Json) Context(org.folio.inventory.common.Context) MappingMetadataDto(org.folio.MappingMetadataDto) EventHandler(org.folio.processing.events.services.handler.EventHandler) HashMap(java.util.HashMap) CompletableFuture(java.util.concurrent.CompletableFuture) MARC_BIBLIOGRAPHIC(org.folio.rest.jaxrs.model.EntityType.MARC_BIBLIOGRAPHIC) ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) Map(java.util.Map) EntityType(org.folio.rest.jaxrs.model.EntityType) MAPPING_PROFILE(org.folio.rest.jaxrs.model.ProfileSnapshotWrapper.ContentType.MAPPING_PROFILE) JsonObject(io.vertx.core.json.JsonObject) Objects.isNull(java.util.Objects.isNull) AsyncResult(io.vertx.core.AsyncResult) MappingProfile(org.folio.MappingProfile) Record(org.folio.rest.jaxrs.model.Record) Promise(io.vertx.core.Promise) DataImportEventPayload(org.folio.DataImportEventPayload) Collectors(java.util.stream.Collectors) String.format(java.lang.String.format) Logger(org.apache.logging.log4j.Logger) EventProcessingException(org.folio.processing.exceptions.EventProcessingException) StringUtils.isBlank(org.apache.commons.lang3.StringUtils.isBlank) EventHandlingUtil(org.folio.inventory.dataimport.handlers.matching.util.EventHandlingUtil) INSTANCE(org.folio.ActionProfile.FolioRecord.INSTANCE) Instance(org.folio.inventory.domain.instances.Instance) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) LogManager(org.apache.logging.log4j.LogManager) DI_SRS_MARC_BIB_RECORD_MODIFIED_READY_FOR_POST_PROCESSING(org.folio.DataImportEventTypes.DI_SRS_MARC_BIB_RECORD_MODIFIED_READY_FOR_POST_PROCESSING) MappingMetadataCache(org.folio.inventory.dataimport.cache.MappingMetadataCache) ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) Instance(org.folio.inventory.domain.instances.Instance) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) JsonObject(io.vertx.core.json.JsonObject) EventProcessingException(org.folio.processing.exceptions.EventProcessingException) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) DataImportEventPayload(org.folio.DataImportEventPayload) CompletableFuture(java.util.concurrent.CompletableFuture) Record(org.folio.rest.jaxrs.model.Record) EventProcessingException(org.folio.processing.exceptions.EventProcessingException)

Example 4 with OptimisticLockingException

use of org.folio.inventory.dataimport.exceptions.OptimisticLockingException in project mod-inventory by folio-org.

the class MarcHoldingsRecordHridSetKafkaHandler method processOLError.

private void processOLError(KafkaConsumerRecord<String, String> value, Promise<String> promise, HashMap<String, String> eventPayload, AsyncResult<HoldingsRecord> ar) {
    int currentRetryNumber = eventPayload.get(CURRENT_RETRY_NUMBER) == null ? 0 : Integer.parseInt(eventPayload.get(CURRENT_RETRY_NUMBER));
    if (currentRetryNumber < MAX_RETRIES_COUNT) {
        eventPayload.put(CURRENT_RETRY_NUMBER, String.valueOf(currentRetryNumber + 1));
        LOGGER.warn("Error updating Holding - {}. Retry MarcHoldingsRecordHridSetKafkaHandler handler...", ar.cause().getMessage());
        handle(value).onComplete(res -> {
            if (res.succeeded()) {
                promise.complete(value.key());
            } else {
                promise.fail(res.cause());
            }
        });
    } else {
        eventPayload.remove(CURRENT_RETRY_NUMBER);
        String errMessage = format("Current retry number %s exceeded given number %s for the Holding update", MAX_RETRIES_COUNT, currentRetryNumber);
        LOGGER.error(errMessage);
        promise.fail(new OptimisticLockingException(errMessage));
    }
}
Also used : OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException)

Example 5 with OptimisticLockingException

use of org.folio.inventory.dataimport.exceptions.OptimisticLockingException in project mod-inventory by folio-org.

the class MarcBibInstanceHridSetKafkaHandler method handle.

@Override
public Future<String> handle(KafkaConsumerRecord<String, String> record) {
    try {
        Promise<String> promise = Promise.promise();
        Event event = OBJECT_MAPPER.readValue(record.value(), Event.class);
        @SuppressWarnings("unchecked") HashMap<String, String> eventPayload = OBJECT_MAPPER.readValue(event.getEventPayload(), HashMap.class);
        Map<String, String> headersMap = KafkaHeaderUtils.kafkaHeadersToMap(record.headers());
        String recordId = headersMap.get(RECORD_ID_HEADER);
        String chunkId = headersMap.get(CHUNK_ID_HEADER);
        String jobExecutionId = eventPayload.get(JOB_EXECUTION_ID_HEADER);
        LOGGER.info("Event payload has been received with event type: {}, recordId: {} by jobExecution: {} and chunkId: {}", event.getEventType(), recordId, jobExecutionId, chunkId);
        if (isEmpty(eventPayload.get(MARC_KEY))) {
            String message = format("Event payload does not contain required data to update Instance with event type: '%s', recordId: '%s' by jobExecution: '%s' and chunkId: '%s'", event.getEventType(), recordId, jobExecutionId, chunkId);
            LOGGER.error(message);
            return Future.failedFuture(message);
        }
        Context context = EventHandlingUtil.constructContext(headersMap.get(OKAPI_TENANT_HEADER), headersMap.get(OKAPI_TOKEN_HEADER), headersMap.get(OKAPI_URL_HEADER));
        Record marcRecord = new JsonObject(eventPayload.get(MARC_KEY)).mapTo(Record.class);
        mappingMetadataCache.get(jobExecutionId, context).map(metadataOptional -> metadataOptional.orElseThrow(() -> new EventProcessingException(format(MAPPING_METADATA_NOT_FOUND_MSG, jobExecutionId)))).onSuccess(mappingMetadataDto -> ensureEventPayloadWithMappingMetadata(eventPayload, mappingMetadataDto)).compose(v -> instanceUpdateDelegate.handle(eventPayload, marcRecord, context)).onComplete(ar -> {
            if (ar.succeeded()) {
                eventPayload.remove(CURRENT_RETRY_NUMBER);
                promise.complete(record.key());
            } else {
                if (ar.cause() instanceof OptimisticLockingException) {
                    processOLError(record, promise, eventPayload, ar);
                } else {
                    eventPayload.remove(CURRENT_RETRY_NUMBER);
                    LOGGER.error("Failed to set MarcBib Hrid by jobExecutionId {}:{}", jobExecutionId, ar.cause());
                    promise.fail(ar.cause());
                }
            }
        });
        return promise.future();
    } catch (Exception e) {
        LOGGER.error(format("Failed to process data import kafka record from topic %s", record.topic()), e);
        return Future.failedFuture(e);
    }
}
Also used : Context(org.folio.inventory.common.Context) MappingMetadataDto(org.folio.MappingMetadataDto) Context(org.folio.inventory.common.Context) OKAPI_TENANT_HEADER(org.folio.rest.util.OkapiConnectionParams.OKAPI_TENANT_HEADER) HashMap(java.util.HashMap) OKAPI_URL_HEADER(org.folio.rest.util.OkapiConnectionParams.OKAPI_URL_HEADER) ObjectMapperTool(org.folio.dbschema.ObjectMapperTool) Map(java.util.Map) JsonObject(io.vertx.core.json.JsonObject) AsyncResult(io.vertx.core.AsyncResult) StringUtils.isEmpty(org.apache.commons.lang3.StringUtils.isEmpty) Event(org.folio.rest.jaxrs.model.Event) Record(org.folio.rest.jaxrs.model.Record) Promise(io.vertx.core.Promise) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) AsyncRecordHandler(org.folio.kafka.AsyncRecordHandler) Future(io.vertx.core.Future) String.format(java.lang.String.format) InstanceUpdateDelegate(org.folio.inventory.dataimport.handlers.actions.InstanceUpdateDelegate) Logger(org.apache.logging.log4j.Logger) EventProcessingException(org.folio.processing.exceptions.EventProcessingException) KafkaConsumerRecord(io.vertx.kafka.client.consumer.KafkaConsumerRecord) EventHandlingUtil(org.folio.inventory.dataimport.handlers.matching.util.EventHandlingUtil) OKAPI_TOKEN_HEADER(org.folio.rest.util.OkapiConnectionParams.OKAPI_TOKEN_HEADER) Instance(org.folio.inventory.domain.instances.Instance) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) LogManager(org.apache.logging.log4j.LogManager) KafkaHeaderUtils(org.folio.kafka.KafkaHeaderUtils) MappingMetadataCache(org.folio.inventory.dataimport.cache.MappingMetadataCache) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) JsonObject(io.vertx.core.json.JsonObject) EventProcessingException(org.folio.processing.exceptions.EventProcessingException) OptimisticLockingException(org.folio.inventory.dataimport.exceptions.OptimisticLockingException) Event(org.folio.rest.jaxrs.model.Event) Record(org.folio.rest.jaxrs.model.Record) KafkaConsumerRecord(io.vertx.kafka.client.consumer.KafkaConsumerRecord) EventProcessingException(org.folio.processing.exceptions.EventProcessingException)

Aggregations

OptimisticLockingException (org.folio.inventory.dataimport.exceptions.OptimisticLockingException)9 HashMap (java.util.HashMap)4 Instance (org.folio.inventory.domain.instances.Instance)4 AsyncResult (io.vertx.core.AsyncResult)3 Promise (io.vertx.core.Promise)3 JsonObject (io.vertx.core.json.JsonObject)3 String.format (java.lang.String.format)3 Map (java.util.Map)3 LogManager (org.apache.logging.log4j.LogManager)3 Logger (org.apache.logging.log4j.Logger)3 MappingMetadataDto (org.folio.MappingMetadataDto)3 Context (org.folio.inventory.common.Context)3 MappingMetadataCache (org.folio.inventory.dataimport.cache.MappingMetadataCache)3 EventProcessingException (org.folio.processing.exceptions.EventProcessingException)3 Record (org.folio.rest.jaxrs.model.Record)3 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 Future (io.vertx.core.Future)2 Json (io.vertx.core.json.Json)2 KafkaConsumerRecord (io.vertx.kafka.client.consumer.KafkaConsumerRecord)2 StringUtils.isEmpty (org.apache.commons.lang3.StringUtils.isEmpty)2