diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java index 7a5c7c78..3eac374c 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/configuration/Registration.java @@ -15,16 +15,15 @@ import com.sap.cds.feature.attachments.handler.applicationservice.UpdateAttachmentsHandler; import com.sap.cds.feature.attachments.handler.applicationservice.helper.ThreadLocalDataStorage; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.CreateAttachmentEvent; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.DefaultModifyAttachmentEventFactory; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEventFactory; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.DoNothingAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.MarkAsDeletedAttachmentEvent; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.UpdateAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.readhelper.AttachmentStatusValidator; import com.sap.cds.feature.attachments.handler.applicationservice.processor.transaction.CreationChangeSetListener; import com.sap.cds.feature.attachments.handler.applicationservice.processor.transaction.ListenerProvider; -import com.sap.cds.feature.attachments.handler.common.DefaultAssociationCascader; -import com.sap.cds.feature.attachments.handler.common.DefaultAttachmentsReader; +import com.sap.cds.feature.attachments.handler.common.AssociationCascader; +import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.feature.attachments.handler.draftservice.DraftActiveAttachmentsHandler; import com.sap.cds.feature.attachments.handler.draftservice.DraftCancelAttachmentsHandler; import com.sap.cds.feature.attachments.handler.draftservice.DraftPatchAttachmentsHandler; @@ -102,7 +101,7 @@ public void eventHandlers(CdsRuntimeConfigurer configurer) { var deleteContentEvent = new MarkAsDeletedAttachmentEvent(outboxedAttachmentService); var eventFactory = buildAttachmentEventFactory(attachmentService, deleteContentEvent, outboxedAttachmentService); - var attachmentsReader = new DefaultAttachmentsReader(new DefaultAssociationCascader(), persistenceService); + var attachmentsReader = new AttachmentsReader(new AssociationCascader(), persistenceService); ThreadLocalDataStorage storage = new ThreadLocalDataStorage(); // register event handlers for application service, if at least one application service is available @@ -157,15 +156,15 @@ private static MalwareScanClient buildMalwareScanClient(CdsEnvironment environme return null; } - private static DefaultModifyAttachmentEventFactory buildAttachmentEventFactory(AttachmentService attachmentService, - ModifyAttachmentEvent deleteContentEvent, AttachmentService outboxedAttachmentService) { + private static ModifyAttachmentEventFactory buildAttachmentEventFactory(AttachmentService attachmentService, + MarkAsDeletedAttachmentEvent deleteContentEvent, AttachmentService outboxedAttachmentService) { ListenerProvider creationChangeSetListener = (contentId, cdsRuntime) -> new CreationChangeSetListener(contentId, cdsRuntime, outboxedAttachmentService); var createAttachmentEvent = new CreateAttachmentEvent(attachmentService, creationChangeSetListener); var updateAttachmentEvent = new UpdateAttachmentEvent(createAttachmentEvent, deleteContentEvent); var doNothingAttachmentEvent = new DoNothingAttachmentEvent(); - return new DefaultModifyAttachmentEventFactory(createAttachmentEvent, updateAttachmentEvent, deleteContentEvent, + return new ModifyAttachmentEventFactory(createAttachmentEvent, updateAttachmentEvent, deleteContentEvent, doNothingAttachmentEvent); } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandler.java index fafd9126..aea9ada6 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandler.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice; +import static java.util.Objects.requireNonNull; + import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -28,9 +30,8 @@ import com.sap.cds.services.utils.OrderConstants; /** - * The class {@link CreateAttachmentsHandler} is an event handler that is - * responsible for creating attachments for entities. - * It is called before a create event is executed. + * The class {@link CreateAttachmentsHandler} is an event handler that is responsible for creating attachments for + * entities. It is called before a create event is executed. */ @ServiceName(value = "*", type = ApplicationService.class) public class CreateAttachmentsHandler implements EventHandler { @@ -42,8 +43,8 @@ public class CreateAttachmentsHandler implements EventHandler { private final CdsDataProcessor processor = CdsDataProcessor.create(); public CreateAttachmentsHandler(ModifyAttachmentEventFactory eventFactory, ThreadDataStorageReader storageReader) { - this.eventFactory = eventFactory; - this.storageReader = storageReader; + this.eventFactory = requireNonNull(eventFactory, "eventFactory must not be null"); + this.storageReader = requireNonNull(storageReader, "storageReader must not be null"); } @Before @@ -61,12 +62,13 @@ public void processBefore(CdsCreateEventContext context, List data) { logger.debug("Processing before create event for entity {}", context.getTarget().getName()); setKeysInData(context.getTarget(), data); - ModifyApplicationHandlerHelper.handleAttachmentForEntities(context.getTarget(), data, new ArrayList<>(), eventFactory, - context); + ModifyApplicationHandlerHelper.handleAttachmentForEntities(context.getTarget(), data, new ArrayList<>(), + eventFactory, context); } private void setKeysInData(CdsEntity entity, List data) { - processor.addGenerator((path, element, type) -> element.isKey() && element.getType().isSimpleType(CdsBaseType.UUID), + processor.addGenerator( + (path, element, type) -> element.isKey() && element.getType().isSimpleType(CdsBaseType.UUID), (path, element, isNull) -> UUID.randomUUID().toString()).process(data, entity); } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandler.java index 0246b963..6246b41b 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandler.java @@ -3,7 +3,10 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice; +import static java.util.Objects.requireNonNull; + import java.io.InputStream; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,7 +14,7 @@ import com.sap.cds.CdsData; import com.sap.cds.CdsDataProcessor; import com.sap.cds.CdsDataProcessor.Converter; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.MarkAsDeletedAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.ApplicationHandlerHelper; import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.services.cds.ApplicationService; @@ -31,12 +34,11 @@ public class DeleteAttachmentsHandler implements EventHandler { private static final Logger logger = LoggerFactory.getLogger(DeleteAttachmentsHandler.class); private final AttachmentsReader attachmentsReader; - private final ModifyAttachmentEvent deleteContentAttachmentEvent; + private final MarkAsDeletedAttachmentEvent deleteEvent; - public DeleteAttachmentsHandler(AttachmentsReader attachmentsReader, - ModifyAttachmentEvent deleteContentAttachmentEvent) { - this.attachmentsReader = attachmentsReader; - this.deleteContentAttachmentEvent = deleteContentAttachmentEvent; + public DeleteAttachmentsHandler(AttachmentsReader attachmentsReader, MarkAsDeletedAttachmentEvent deleteEvent) { + this.attachmentsReader = requireNonNull(attachmentsReader, "attachmentsReader must not be null"); + this.deleteEvent = requireNonNull(deleteEvent, "deleteEvent must not be null"); } @Before @@ -44,12 +46,14 @@ public DeleteAttachmentsHandler(AttachmentsReader attachmentsReader, public void processBefore(CdsDeleteEventContext context) { logger.debug("Processing before delete event for entity {}", context.getTarget().getName()); - var attachments = attachmentsReader.readAttachments(context.getModel(), context.getTarget(), context.getCqn()); + List attachments = attachmentsReader.readAttachments(context.getModel(), context.getTarget(), + context.getCqn()); - Converter converter = (path, element, value) -> deleteContentAttachmentEvent.processEvent(path, - (InputStream) value, CdsData.create(path.target().values()), context); + Converter converter = (path, element, value) -> deleteEvent.processEvent(path, (InputStream) value, + CdsData.create(path.target().values()), context); - CdsDataProcessor.create().addConverter(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, converter).process(attachments, context.getTarget()); + CdsDataProcessor.create().addConverter(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, converter) + .process(attachments, context.getTarget()); } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/ReadAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/ReadAttachmentsHandler.java index 5a72a4ed..85ac1beb 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/ReadAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/ReadAttachmentsHandler.java @@ -26,6 +26,7 @@ import com.sap.cds.feature.attachments.service.AttachmentService; import com.sap.cds.feature.attachments.service.malware.AsyncMalwareScanExecutor; import com.sap.cds.ql.CQL; +import com.sap.cds.ql.cqn.CqnSelect; import com.sap.cds.ql.cqn.Path; import com.sap.cds.reflect.CdsAssociationType; import com.sap.cds.reflect.CdsElementDefinition; @@ -41,13 +42,11 @@ import com.sap.cds.services.handler.annotations.ServiceName; /** - * The class {@link ReadAttachmentsHandler} is an event handler that is - * responsible for reading attachments for entities. - * In the before read event, it modifies the CQN to include the content ID and status. - * In the after read event, it adds a proxy for the stream of the attachments service to the data. - * Only if the data are read the proxy forwards the request to the attachment service to read the attachment. - * This is needed to have a filled stream in the data to enable the OData V4 adapter to enrich the data that - * a link to the content can be shown on the UI. + * The class {@link ReadAttachmentsHandler} is an event handler that is responsible for reading attachments for + * entities. In the before read event, it modifies the CQN to include the content ID and status. In the after read + * event, it adds a proxy for the stream of the attachments service to the data. Only if the data are read the proxy + * forwards the request to the attachment service to read the attachment. This is needed to have a filled stream in the + * data to enable the OData V4 adapter to enrich the data that a link to the content can be shown on the UI. */ @ServiceName(value = "*", type = ApplicationService.class) public class ReadAttachmentsHandler implements EventHandler { @@ -58,7 +57,7 @@ public class ReadAttachmentsHandler implements EventHandler { private final AttachmentStatusValidator attachmentStatusValidator; private final AsyncMalwareScanExecutor asyncMalwareScanExecutor; - public ReadAttachmentsHandler(AttachmentService attachmentService, + public ReadAttachmentsHandler(AttachmentService attachmentService, AttachmentStatusValidator attachmentStatusValidator, AsyncMalwareScanExecutor asyncMalwareScanExecutor) { this.attachmentService = attachmentService; this.attachmentStatusValidator = attachmentStatusValidator; @@ -70,10 +69,10 @@ public ReadAttachmentsHandler(AttachmentService attachmentService, public void processBefore(CdsReadEventContext context) { logger.debug("Processing before read event for entity {}", context.getTarget().getName()); - var cdsModel = context.getModel(); - var fieldNames = getAttachmentAssociations(cdsModel, context.getTarget(), "", new ArrayList<>()); + CdsModel cdsModel = context.getModel(); + List fieldNames = getAttachmentAssociations(cdsModel, context.getTarget(), "", new ArrayList<>()); if (!fieldNames.isEmpty()) { - var resultCqn = CQL.copy(context.getCqn(), new BeforeReadItemsModifier(fieldNames)); + CqnSelect resultCqn = CQL.copy(context.getCqn(), new BeforeReadItemsModifier(fieldNames)); context.setCqn(resultCqn); } } @@ -88,41 +87,42 @@ public void processAfter(CdsReadEventContext context, List data) { Converter converter = (path, element, value) -> { logger.info("Processing after read event for entity {}", element.getName()); - var contentId = (String) path.target().values().get(Attachments.CONTENT_ID); - var status = (String) path.target().values().get(Attachments.STATUS); - var content = (InputStream) path.target().values().get(Attachments.CONTENT); - var contentExists = Objects.nonNull(content); + String contentId = (String) path.target().values().get(Attachments.CONTENT_ID); + String status = (String) path.target().values().get(Attachments.STATUS); + InputStream content = (InputStream) path.target().values().get(Attachments.CONTENT); + boolean contentExists = Objects.nonNull(content); if (Objects.nonNull(contentId) || contentExists) { verifyStatus(path, status, contentId, contentExists); - Supplier supplier = Objects.nonNull(content) ? () -> content : () -> attachmentService.readAttachment( - contentId); + Supplier supplier = Objects.nonNull(content) ? () -> content + : () -> attachmentService.readAttachment(contentId); return new LazyProxyInputStream(supplier, attachmentStatusValidator, status); } else { return value; } }; - CdsDataProcessor.create().addConverter(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, converter).process(data, context.getTarget()); + CdsDataProcessor.create().addConverter(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, converter).process(data, + context.getTarget()); } private List getAttachmentAssociations(CdsModel model, CdsEntity entity, String associationName, List processedEntities) { - var associationNames = new ArrayList(); + List associationNames = new ArrayList(); if (ApplicationHandlerHelper.isMediaEntity(entity)) { associationNames.add(associationName); } - Map annotatedEntitiesMap = entity.associations() - .collect(Collectors.toMap(CdsElementDefinition::getName, - element -> element.getType().as(CdsAssociationType.class).getTarget())); + Map annotatedEntitiesMap = entity.associations().collect(Collectors.toMap( + CdsElementDefinition::getName, element -> element.getType().as(CdsAssociationType.class).getTarget())); if (annotatedEntitiesMap.isEmpty()) { return associationNames; } for (var associatedElement : annotatedEntitiesMap.entrySet()) { - if (!associationNames.contains(associatedElement.getKey()) && !processedEntities.contains( - associatedElement.getKey()) && !Drafts.SIBLING_ENTITY.equals(associatedElement.getKey())) { + if (!associationNames.contains(associatedElement.getKey()) + && !processedEntities.contains(associatedElement.getKey()) + && !Drafts.SIBLING_ENTITY.equals(associatedElement.getKey())) { processedEntities.add(associatedElement.getKey()); var result = getAttachmentAssociations(model, associatedElement.getValue(), associatedElement.getKey(), processedEntities); diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandler.java index c0b207b4..6f2676c3 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandler.java @@ -20,7 +20,7 @@ import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.feature.attachments.service.AttachmentService; import com.sap.cds.feature.attachments.service.model.service.MarkAsDeletedInput; -import com.sap.cds.ql.cqn.CqnFilterableStatement; +import com.sap.cds.ql.cqn.CqnSelect; import com.sap.cds.ql.cqn.CqnUpdate; import com.sap.cds.reflect.CdsEntity; import com.sap.cds.services.cds.ApplicationService; @@ -34,11 +34,9 @@ import com.sap.cds.services.utils.model.CqnUtils; /** - * The class {@link UpdateAttachmentsHandler} is an event handler that - * is called before an update event is executed. - * As updates in draft entities or non-draft entities can also be - * create-events, update-events or delete-events the handler needs to distinguish between - * the different cases. + * The class {@link UpdateAttachmentsHandler} is an event handler that is called before an update event is executed. As + * updates in draft entities or non-draft entities can also be create-events, update-events or delete-events the handler + * needs to distinguish between the different cases. */ @ServiceName(value = "*", type = ApplicationService.class) public class UpdateAttachmentsHandler implements EventHandler { @@ -47,14 +45,14 @@ public class UpdateAttachmentsHandler implements EventHandler { private final ModifyAttachmentEventFactory eventFactory; private final AttachmentsReader attachmentsReader; - private final AttachmentService outboxedAttachmentService; + private final AttachmentService attachmentService; private final ThreadDataStorageReader storageReader; public UpdateAttachmentsHandler(ModifyAttachmentEventFactory eventFactory, AttachmentsReader attachmentsReader, - AttachmentService outboxedAttachmentService, ThreadDataStorageReader storageReader) { + AttachmentService attachmentService, ThreadDataStorageReader storageReader) { this.eventFactory = eventFactory; this.attachmentsReader = attachmentsReader; - this.outboxedAttachmentService = outboxedAttachmentService; + this.attachmentService = attachmentService; this.storageReader = storageReader; } @@ -71,20 +69,21 @@ public void processBefore(CdsUpdateEventContext context, List data) { } private void doUpdate(CdsUpdateEventContext context, List data) { - var target = context.getTarget(); - var noContentInData = ApplicationHandlerHelper.noContentFieldInData(target, data); - var associationsAreUnchanged = associationsAreUnchanged(target, data); + CdsEntity target = context.getTarget(); + boolean noContentInData = ApplicationHandlerHelper.noContentFieldInData(target, data); + boolean associationsAreUnchanged = associationsAreUnchanged(target, data); if (noContentInData && associationsAreUnchanged) { return; } logger.debug("Processing before update event for entity {}", target.getName()); - var select = getSelect(context.getCqn(), context.getTarget()); - var attachments = attachmentsReader.readAttachments(context.getModel(), target, select); + CqnSelect select = getSelect(context.getCqn(), context.getTarget()); + List attachments = attachmentsReader.readAttachments(context.getModel(), target, select); - var condensedAttachments = ApplicationHandlerHelper.condenseData(attachments, target); - ModifyApplicationHandlerHelper.handleAttachmentForEntities(target, data, condensedAttachments, eventFactory, context); + List condensedAttachments = ApplicationHandlerHelper.condenseData(attachments, target); + ModifyApplicationHandlerHelper.handleAttachmentForEntities(target, data, condensedAttachments, eventFactory, + context); if (!associationsAreUnchanged) { deleteRemovedAttachments(attachments, data, target, context.getUserInfo()); @@ -93,27 +92,29 @@ private void doUpdate(CdsUpdateEventContext context, List data) { private boolean associationsAreUnchanged(CdsEntity entity, List data) { // TODO: check if this should be replaced with entity.assocations().noneMatch(...) - return entity.compositions().noneMatch( - association -> data.stream().anyMatch(d -> d.containsKey(association.getName()))); + return entity.compositions() + .noneMatch(association -> data.stream().anyMatch(d -> d.containsKey(association.getName()))); } - private CqnFilterableStatement getSelect(CqnUpdate update, CdsEntity target) { + private CqnSelect getSelect(CqnUpdate update, CdsEntity target) { return CqnUtils.toSelect(update, target); } - private void deleteRemovedAttachments(List exitingDataList, List updatedDataList, CdsEntity entity, UserInfo userInfo) { + private void deleteRemovedAttachments(List exitingDataList, List updatedDataList, + CdsEntity entity, UserInfo userInfo) { var condensedUpdatedData = ApplicationHandlerHelper.condenseData(updatedDataList, entity); Validator validator = (path, element, value) -> { var keys = ApplicationHandlerHelper.removeDraftKey(path.target().keys()); - var entryExists = condensedUpdatedData.stream().anyMatch( - updatedData -> ApplicationHandlerHelper.areKeysInData(keys, updatedData)); + var entryExists = condensedUpdatedData.stream() + .anyMatch(updatedData -> ApplicationHandlerHelper.areKeysInData(keys, updatedData)); if (!entryExists) { var contentId = (String) path.target().values().get(Attachments.CONTENT_ID); - outboxedAttachmentService.markAttachmentAsDeleted(new MarkAsDeletedInput(contentId, userInfo)); + attachmentService.markAttachmentAsDeleted(new MarkAsDeletedInput(contentId, userInfo)); } }; - CdsDataProcessor.create().addValidator(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, validator).process(exitingDataList, entity); + CdsDataProcessor.create().addValidator(ApplicationHandlerHelper.MEDIA_CONTENT_FILTER, validator) + .process(exitingDataList, entity); } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/helper/ModifyApplicationHandlerHelper.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/helper/ModifyApplicationHandlerHelper.java index 28826900..dd2dd565 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/helper/ModifyApplicationHandlerHelper.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/helper/ModifyApplicationHandlerHelper.java @@ -11,8 +11,8 @@ import com.sap.cds.CdsDataProcessor; import com.sap.cds.CdsDataProcessor.Converter; import com.sap.cds.feature.attachments.generated.cds4j.sap.attachments.Attachments; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEventFactory; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.ApplicationHandlerHelper; import com.sap.cds.ql.cqn.Path; import com.sap.cds.reflect.CdsEntity; diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/CreateAttachmentEvent.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/CreateAttachmentEvent.java index d05141f1..3ae7db84 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/CreateAttachmentEvent.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/CreateAttachmentEvent.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents; +import static java.util.Objects.requireNonNull; + import java.io.InputStream; import java.util.Map; import java.util.Objects; @@ -33,14 +35,8 @@ public class CreateAttachmentEvent implements ModifyAttachmentEvent { private final ListenerProvider listenerProvider; public CreateAttachmentEvent(AttachmentService attachmentService, ListenerProvider listenerProvider) { - this.attachmentService = attachmentService; - this.listenerProvider = listenerProvider; - } - - private static Optional getFieldValue(String fieldName, Map values, CdsData existingData) { - var annotationValue = values.get(fieldName); - var value = Objects.nonNull(annotationValue) ? annotationValue : existingData.get(fieldName); - return Optional.ofNullable((String) value); + this.attachmentService = requireNonNull(attachmentService, "attachmentService must not be null"); + this.listenerProvider = requireNonNull(listenerProvider, "listenerProvider must not be null"); } @Override @@ -63,4 +59,9 @@ public InputStream processEvent(Path path, InputStream content, CdsData existing return result.isInternalStored() ? content : null; } + private static Optional getFieldValue(String fieldName, Map values, CdsData existingData) { + var annotationValue = values.get(fieldName); + var value = Objects.nonNull(annotationValue) ? annotationValue : existingData.get(fieldName); + return Optional.ofNullable((String) value); + } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactory.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactory.java deleted file mode 100644 index 2b9d7137..00000000 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************************************** - * (C) 2019-2025 SAP SE or an SAP affiliate company. All rights reserved. * - **************************************************************************/ -package com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents; - -import java.io.InputStream; -import java.util.Objects; -import java.util.Optional; - -import com.sap.cds.CdsData; -import com.sap.cds.feature.attachments.generated.cds4j.sap.attachments.Attachments; -import com.sap.cds.feature.attachments.service.AttachmentService; - -/** - * The class {@link DefaultModifyAttachmentEventFactory} is a factory class that creates the corresponding event for the - * attachment service {@link AttachmentService}. The class is used to determine the event that should be executed based - * on the content, the contentId and the existingData.
- * The events could be: - *
    - *
  • create
  • - *
  • update
  • - *
  • deleteContent
  • - *
  • doNothing
  • - *
- */ -public class DefaultModifyAttachmentEventFactory implements ModifyAttachmentEventFactory { - - private final ModifyAttachmentEvent createEvent; - private final ModifyAttachmentEvent updateEvent; - private final ModifyAttachmentEvent deleteContentEvent; - private final ModifyAttachmentEvent doNothingEvent; - - public DefaultModifyAttachmentEventFactory(ModifyAttachmentEvent createEvent, ModifyAttachmentEvent updateEvent, - ModifyAttachmentEvent deleteContentEvent, ModifyAttachmentEvent doNothingEvent) { - this.createEvent = createEvent; - this.updateEvent = updateEvent; - this.deleteContentEvent = deleteContentEvent; - this.doNothingEvent = doNothingEvent; - } - - @Override - public ModifyAttachmentEvent getEvent(InputStream content, String contentId, CdsData existingData) { - var existingContentId = existingData.get(Attachments.CONTENT_ID); - var event = contentId != null ? handleExistingContentId(content, contentId, (String) existingContentId) - : handleNonExistingContentId(content, existingContentId); - return event.orElse(doNothingEvent); - } - - private Optional handleExistingContentId(InputStream content, String contentId, - String existingContentId) { - ModifyAttachmentEvent event = null; - if (contentId.equals(existingContentId) && Objects.nonNull(content)) { - event = updateEvent; - } - if (Objects.nonNull(existingContentId) && !contentId.equals(existingContentId) && Objects.isNull(content)) { - event = deleteContentEvent; - } - if (Objects.nonNull(existingContentId) && !contentId.equals(existingContentId) && Objects.nonNull(content)) { - event = updateEvent; - } - - return Optional.ofNullable(event); - } - - private Optional handleNonExistingContentId(Object content, Object existingContentId) { - ModifyAttachmentEvent event = null; - if (Objects.nonNull(existingContentId)) { - if (Objects.nonNull(content)) { - event = updateEvent; - } else { - event = deleteContentEvent; - } - } else { - if (Objects.nonNull(content)) { - event = createEvent; - } - } - return Optional.ofNullable(event); - } - -} diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DoNothingAttachmentEvent.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DoNothingAttachmentEvent.java index 5d06b356..35bdf6f1 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DoNothingAttachmentEvent.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DoNothingAttachmentEvent.java @@ -13,8 +13,8 @@ import com.sap.cds.services.EventContext; /** - * The class {@link DoNothingAttachmentEvent} does nothing. - * The event factory uses this class to create an event that does nothing. + * The class {@link DoNothingAttachmentEvent} does nothing. The event factory uses this class to create an event that + * does nothing. */ public class DoNothingAttachmentEvent implements ModifyAttachmentEvent { diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/MarkAsDeletedAttachmentEvent.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/MarkAsDeletedAttachmentEvent.java index ca2d5e2d..30313360 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/MarkAsDeletedAttachmentEvent.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/MarkAsDeletedAttachmentEvent.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents; +import static java.util.Objects.requireNonNull; + import java.io.InputStream; import java.util.Objects; @@ -19,30 +21,30 @@ import com.sap.cds.services.draft.DraftService; /** - * The class {@link MarkAsDeletedAttachmentEvent} handles the mark of deletion of an attachment. - * It calls the {@link AttachmentService} to mark the attachment as deleted. -*/ + * The class {@link MarkAsDeletedAttachmentEvent} handles the mark of deletion of an attachment. It calls the + * {@link AttachmentService} to mark the attachment as deleted. + */ public class MarkAsDeletedAttachmentEvent implements ModifyAttachmentEvent { private static final Logger logger = LoggerFactory.getLogger(MarkAsDeletedAttachmentEvent.class); - private final AttachmentService outboxedAttachmentService; + private final AttachmentService attachmentService; - public MarkAsDeletedAttachmentEvent(AttachmentService outboxedAttachmentService) { - this.outboxedAttachmentService = outboxedAttachmentService; + public MarkAsDeletedAttachmentEvent(AttachmentService attachmentService) { + this.attachmentService = requireNonNull(attachmentService, "attachmentService must not be null"); } @Override public InputStream processEvent(Path path, InputStream content, CdsData existingData, EventContext eventContext) { - var qualifiedName = eventContext.getTarget().getQualifiedName(); + String qualifiedName = eventContext.getTarget().getQualifiedName(); logger.debug("Processing the event for calling attachment service with mark as delete event for entity {}", qualifiedName); - if (ApplicationHandlerHelper.doesContentIdExistsBefore(existingData) && !DraftService.EVENT_DRAFT_PATCH.equals( - eventContext.getEvent())) { + if (ApplicationHandlerHelper.doesContentIdExistsBefore(existingData) + && !DraftService.EVENT_DRAFT_PATCH.equals(eventContext.getEvent())) { logger.debug("Calling attachment service with mark as delete event for entity {}", qualifiedName); - var contentId = (String) existingData.get(Attachments.CONTENT_ID); - outboxedAttachmentService.markAttachmentAsDeleted(new MarkAsDeletedInput(contentId, eventContext.getUserInfo())); + String contentId = (String) existingData.get(Attachments.CONTENT_ID); + attachmentService.markAttachmentAsDeleted(new MarkAsDeletedInput(contentId, eventContext.getUserInfo())); } else { logger.debug( "Do NOT call attachment service with mark as delete event for entity {} as no document id found in existing data and event is DRAFT_PATCH event", @@ -50,8 +52,8 @@ public InputStream processEvent(Path path, InputStream content, CdsData existing } if (Objects.nonNull(path)) { var newContentId = path.target().values().get(Attachments.CONTENT_ID); - if (Objects.nonNull(newContentId) && newContentId.equals(existingData.get(Attachments.CONTENT_ID)) || !path.target() - .values().containsKey(Attachments.CONTENT_ID)) { + if (Objects.nonNull(newContentId) && newContentId.equals(existingData.get(Attachments.CONTENT_ID)) + || !path.target().values().containsKey(Attachments.CONTENT_ID)) { path.target().values().put(Attachments.CONTENT_ID, null); path.target().values().put(Attachments.STATUS, null); path.target().values().put(Attachments.SCANNED_AT, null); diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEvent.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEvent.java index b616d47c..0e8802c4 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEvent.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEvent.java @@ -22,7 +22,7 @@ public interface ModifyAttachmentEvent { * @param content the content of the attachment * @param existingData existing data * @param eventContext the current event context - * @return + * @return the processed content */ InputStream processEvent(Path path, InputStream content, CdsData existingData, EventContext eventContext); diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactory.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactory.java index c6d30479..1aba0752 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactory.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactory.java @@ -3,27 +3,88 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents; +import static java.util.Objects.requireNonNull; + import java.io.InputStream; +import java.util.Objects; +import java.util.Optional; import com.sap.cds.CdsData; +import com.sap.cds.feature.attachments.generated.cds4j.sap.attachments.Attachments; import com.sap.cds.feature.attachments.service.AttachmentService; /** - * The class {@link ModifyAttachmentEventFactory} is a factory - * that creates the corresponding event for the attachment service {@link AttachmentService}. - * The class is used to determine the event that should be executed based on the content, - * the contentId and the existingData. + * The class {@link ModifyAttachmentEventFactory} is a factory class that creates the corresponding event for the + * attachment service {@link AttachmentService}. The class is used to determine the event that should be executed based + * on the content, the contentId and the existingData.
+ * The events could be: + *
    + *
  • create
  • + *
  • update
  • + *
  • deleteContent
  • + *
  • doNothing
  • + *
*/ -public interface ModifyAttachmentEventFactory { +public class ModifyAttachmentEventFactory { + + private final CreateAttachmentEvent createEvent; + private final UpdateAttachmentEvent updateEvent; + private final MarkAsDeletedAttachmentEvent deleteEvent; + private final DoNothingAttachmentEvent doNothingEvent; + + public ModifyAttachmentEventFactory(CreateAttachmentEvent createEvent, UpdateAttachmentEvent updateEvent, + MarkAsDeletedAttachmentEvent deleteEvent, DoNothingAttachmentEvent doNothingEvent) { + this.createEvent = requireNonNull(createEvent, "createEvent must not be null"); + this.updateEvent = requireNonNull(updateEvent, "updateEvent must not be null"); + this.deleteEvent = requireNonNull(deleteEvent, "deleteEvent must not be null"); + this.doNothingEvent = requireNonNull(doNothingEvent, "doNothingEvent must not be null"); + } /** * Returns the event that should be executed based on the given parameters. * - * @param content the optional content as {@link InputStream} - * @param contentId the optional content id - * @param existingData the existing {@link CdsData data} + * @param content the optional content as {@link InputStream} + * @param contentId the optional content id + * @param existingData the existing {@link CdsData data} * @return the corresponding {@link ModifyAttachmentEvent} that should be executed */ - ModifyAttachmentEvent getEvent(InputStream content, String contentId, CdsData existingData); + public ModifyAttachmentEvent getEvent(InputStream content, String contentId, CdsData existingData) { + var existingContentId = existingData.get(Attachments.CONTENT_ID); + var event = contentId != null ? handleExistingContentId(content, contentId, (String) existingContentId) + : handleNonExistingContentId(content, existingContentId); + return event.orElse(doNothingEvent); + } + + private Optional handleExistingContentId(InputStream content, String contentId, + String existingContentId) { + ModifyAttachmentEvent event = null; + if (contentId.equals(existingContentId) && Objects.nonNull(content)) { + event = updateEvent; + } + if (Objects.nonNull(existingContentId) && !contentId.equals(existingContentId) && Objects.isNull(content)) { + event = deleteEvent; + } + if (Objects.nonNull(existingContentId) && !contentId.equals(existingContentId) && Objects.nonNull(content)) { + event = updateEvent; + } + + return Optional.ofNullable(event); + } + + private Optional handleNonExistingContentId(Object content, Object existingContentId) { + ModifyAttachmentEvent event = null; + if (Objects.nonNull(existingContentId)) { + if (Objects.nonNull(content)) { + event = updateEvent; + } else { + event = deleteEvent; + } + } else { + if (Objects.nonNull(content)) { + event = createEvent; + } + } + return Optional.ofNullable(event); + } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEvent.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEvent.java index 034b1007..d26b8d14 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEvent.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEvent.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents; +import static java.util.Objects.requireNonNull; + import java.io.InputStream; import org.slf4j.Logger; @@ -14,22 +16,22 @@ import com.sap.cds.services.EventContext; /** - * The class {@link UpdateAttachmentEvent} is an implementation of the {@link ModifyAttachmentEvent}. - * The class is used to update an attachment by calling the mark as deleted and create method - * of the attachment service {@link AttachmentService}. - * To call these attachment service events the class calls the delete and create event implementation. + * The class {@link UpdateAttachmentEvent} is an implementation of the {@link ModifyAttachmentEvent}. The class is used + * to update an attachment by calling the mark as deleted and create method of the attachment service + * {@link AttachmentService}. To call these attachment service events the class calls the delete and create event + * implementation. */ public class UpdateAttachmentEvent implements ModifyAttachmentEvent { private static final Logger logger = LoggerFactory.getLogger(UpdateAttachmentEvent.class); - private final ModifyAttachmentEvent createAttachmentEvent; - private final ModifyAttachmentEvent deleteAttachmentEvent; + private final CreateAttachmentEvent createEvent; + private final MarkAsDeletedAttachmentEvent deleteEvent; - public UpdateAttachmentEvent(ModifyAttachmentEvent createAttachmentEvent, - ModifyAttachmentEvent deleteAttachmentEvent) { - this.createAttachmentEvent = createAttachmentEvent; - this.deleteAttachmentEvent = deleteAttachmentEvent; + public UpdateAttachmentEvent(CreateAttachmentEvent createEvent, + MarkAsDeletedAttachmentEvent deleteAttachmentEvent) { + this.createEvent = requireNonNull(createEvent, "createEvent must not be null"); + this.deleteEvent = requireNonNull(deleteAttachmentEvent, "deleteAttachmentEvent must not be null"); } @Override @@ -37,8 +39,8 @@ public InputStream processEvent(Path path, InputStream content, CdsData existing logger.debug("Processing UPDATE event by calling attachment service with create and delete event for entity {}", path.target().entity().getQualifiedName()); - deleteAttachmentEvent.processEvent(path, content, existingData, eventContext); - return createAttachmentEvent.processEvent(path, content, existingData, eventContext); + deleteEvent.processEvent(path, content, existingData, eventContext); + return createEvent.processEvent(path, content, existingData, eventContext); } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationCascader.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationCascader.java index 289f3aa5..322842da 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationCascader.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationCascader.java @@ -3,15 +3,91 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.common; -import com.sap.cds.feature.attachments.handler.common.model.NodeTree; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.sap.cds.reflect.CdsAssociationType; +import com.sap.cds.reflect.CdsElementDefinition; import com.sap.cds.reflect.CdsEntity; import com.sap.cds.reflect.CdsModel; /** - * The interface {@link AssociationCascader} is used to find the entity path. + * The class {@link AssociationCascader} is used to find entity paths + * to all media resource entities for a given data model. + * The path information is returned in a node tree which starts from the given entity. + * Only composition associations are considered. */ -public interface AssociationCascader { +public class AssociationCascader { + + private static final Logger logger = LoggerFactory.getLogger(AssociationCascader.class); + + public NodeTree findEntityPath(CdsModel model, CdsEntity entity) { + logger.debug("Start finding path to attachments for entity {}", entity.getQualifiedName()); + var firstList = new LinkedList(); + var internalResultList = getAttachmentAssociationPath(model, entity, "", firstList, + new ArrayList<>(List.of(entity.getQualifiedName()))); + + var rootTree = new NodeTree(new AssociationIdentifier("", entity.getQualifiedName())); + internalResultList.forEach(rootTree::addPath); + + logger.debug("Found path to attachments for entity {}: {}", entity.getQualifiedName(), rootTree); + return rootTree; + } + + private List> getAttachmentAssociationPath(CdsModel model, CdsEntity entity, + String associationName, LinkedList firstList, List processedEntities) { + var internalResultList = new ArrayList>(); + var currentList = new AtomicReference>(); + var localProcessEntities = new ArrayList(); + currentList.set(new LinkedList<>()); + + var isMediaEntity = ApplicationHandlerHelper.isMediaEntity(entity); + if (isMediaEntity) { + var identifier = new AssociationIdentifier(associationName, entity.getQualifiedName()); + firstList.addLast(identifier); + } + + if (isMediaEntity) { + internalResultList.add(firstList); + return internalResultList; + } + + Map associations = entity.elements().filter( + element -> element.getType().isAssociation() && element.getType().as(CdsAssociationType.class).isComposition()) + .collect(Collectors.toMap(CdsElementDefinition::getName, + element -> element.getType().as(CdsAssociationType.class).getTarget())); + + if (associations.isEmpty()) { + return internalResultList; + } + + var newListNeeded = false; + for (var associatedElement : associations.entrySet()) { + if (!processedEntities.contains(associatedElement.getValue().getQualifiedName())) { + if (newListNeeded) { + currentList.set(new LinkedList<>()); + currentList.get().addAll(firstList); + processedEntities = localProcessEntities; + } else { + firstList.add(new AssociationIdentifier(associationName, entity.getQualifiedName())); + currentList.get().addAll(firstList); + localProcessEntities = new ArrayList<>(processedEntities); + } + processedEntities.add(associatedElement.getValue().getQualifiedName()); + newListNeeded = true; + var result = getAttachmentAssociationPath(model, associatedElement.getValue(), associatedElement.getKey(), + currentList.get(), processedEntities); + internalResultList.addAll(result); + } + } - NodeTree findEntityPath(CdsModel model, CdsEntity entity); + return internalResultList; + } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/AssociationIdentifier.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationIdentifier.java similarity index 69% rename from cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/AssociationIdentifier.java rename to cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationIdentifier.java index 79d58f7f..e6688d63 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/AssociationIdentifier.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AssociationIdentifier.java @@ -1,13 +1,14 @@ /************************************************************************** * (C) 2019-2025 SAP SE or an SAP affiliate company. All rights reserved. * **************************************************************************/ -package com.sap.cds.feature.attachments.handler.common.model; +package com.sap.cds.feature.attachments.handler.common; /** - * This record is a simple data class that holds the association name and the full entity name. + * This record is a simple data class that holds the association name and the + * full entity name. * * @param associationName the association name * @param fullEntityName the full entity name */ -public record AssociationIdentifier(String associationName, String fullEntityName) { +record AssociationIdentifier(String associationName, String fullEntityName) { } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReader.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReader.java index 544bd184..1287fd4b 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReader.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReader.java @@ -3,18 +3,77 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.common; +import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.util.Objects.requireNonNull; import com.sap.cds.CdsData; +import com.sap.cds.Result; +import com.sap.cds.ql.CQL; +import com.sap.cds.ql.Expand; +import com.sap.cds.ql.Select; +import com.sap.cds.ql.StructuredType; import com.sap.cds.ql.cqn.CqnFilterableStatement; import com.sap.cds.reflect.CdsEntity; import com.sap.cds.reflect.CdsModel; +import com.sap.cds.services.persistence.PersistenceService; /** - * The interface {@link AttachmentsReader} is used to read attachments from the database. + * The class {@link AttachmentsReader} is used to deep read attachments from the + * database for a determined path from the given entity to the media entity. The + * class uses the {@link AssociationCascader} to find the entity path. + *

+ * The returned data is deep including the path structure to the media entity. */ -public interface AttachmentsReader { +public class AttachmentsReader { + + private static final Logger logger = LoggerFactory.getLogger(AttachmentsReader.class); + + private final AssociationCascader cascader; + private final PersistenceService persistence; + + public AttachmentsReader(AssociationCascader cascader, PersistenceService persistence) { + this.cascader = requireNonNull(cascader, "cascader must not be null"); + this.persistence = requireNonNull(persistence, "persistence must not be null"); + } + + public List readAttachments(CdsModel model, CdsEntity entity, CqnFilterableStatement statement) { + logger.debug("Start reading attachments for entity {}", entity.getQualifiedName()); + + NodeTree nodePath = cascader.findEntityPath(model, entity); + List> expandList = buildExpandList(nodePath); + + Select select = !expandList.isEmpty() ? Select.from(statement.ref()).columns(expandList) + : Select.from(statement.ref()).columns(StructuredType::_all); + statement.where().ifPresent(select::where); + + Result result = persistence.run(select); + List cdsData = result.listOf(CdsData.class); + logResultData(entity, cdsData); + return cdsData; + } + + private List> buildExpandList(NodeTree root) { + List> expandResultList = new ArrayList<>(); + root.getChildren().forEach(child -> expandResultList.add(buildExpandFromTree(child))); + + return expandResultList; + } + + private Expand buildExpandFromTree(NodeTree node) { + return node.getChildren().isEmpty() ? CQL.to(node.getIdentifier().associationName()).expand() + : CQL.to(node.getIdentifier().associationName()) + .expand(node.getChildren().stream().map(this::buildExpandFromTree).toList()); + } - List readAttachments(CdsModel model, CdsEntity entity, CqnFilterableStatement statement); + private static void logResultData(CdsEntity entity, List cdsData) { + logger.debug("Read attachments for entity {}: lines {}", entity.getQualifiedName(), cdsData.size()); + if (logger.isTraceEnabled()) { + cdsData.forEach(data -> logger.trace("Read attachment data: {}", data)); + } + } } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascader.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascader.java deleted file mode 100644 index 7bee9863..00000000 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascader.java +++ /dev/null @@ -1,97 +0,0 @@ -/************************************************************************** - * (C) 2019-2025 SAP SE or an SAP affiliate company. All rights reserved. * - **************************************************************************/ -package com.sap.cds.feature.attachments.handler.common; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sap.cds.feature.attachments.handler.common.model.AssociationIdentifier; -import com.sap.cds.feature.attachments.handler.common.model.NodeTree; -import com.sap.cds.reflect.CdsAssociationType; -import com.sap.cds.reflect.CdsElementDefinition; -import com.sap.cds.reflect.CdsEntity; -import com.sap.cds.reflect.CdsModel; - -/** - * The class {@link DefaultAssociationCascader} is used to find entity paths - * to all media resource entities for a given data model. - * The path information is returned in a node tree which starts from the given entity. - * Only composition associations are considered. - */ -public class DefaultAssociationCascader implements AssociationCascader { - - private static final Logger logger = LoggerFactory.getLogger(DefaultAssociationCascader.class); - - @Override - public NodeTree findEntityPath(CdsModel model, CdsEntity entity) { - logger.debug("Start finding path to attachments for entity {}", entity.getQualifiedName()); - var firstList = new LinkedList(); - var internalResultList = getAttachmentAssociationPath(model, entity, "", firstList, - new ArrayList<>(List.of(entity.getQualifiedName()))); - - var rootTree = new NodeTree(new AssociationIdentifier("", entity.getQualifiedName())); - internalResultList.forEach(rootTree::addPath); - - logger.debug("Found path to attachments for entity {}: {}", entity.getQualifiedName(), rootTree); - return rootTree; - } - - private List> getAttachmentAssociationPath(CdsModel model, CdsEntity entity, - String associationName, LinkedList firstList, List processedEntities) { - var internalResultList = new ArrayList>(); - var currentList = new AtomicReference>(); - var localProcessEntities = new ArrayList(); - currentList.set(new LinkedList<>()); - - var isMediaEntity = ApplicationHandlerHelper.isMediaEntity(entity); - if (isMediaEntity) { - var identifier = new AssociationIdentifier(associationName, entity.getQualifiedName()); - firstList.addLast(identifier); - } - - if (isMediaEntity) { - internalResultList.add(firstList); - return internalResultList; - } - - Map associations = entity.elements().filter( - element -> element.getType().isAssociation() && element.getType().as(CdsAssociationType.class).isComposition()) - .collect(Collectors.toMap(CdsElementDefinition::getName, - element -> element.getType().as(CdsAssociationType.class).getTarget())); - - if (associations.isEmpty()) { - return internalResultList; - } - - var newListNeeded = false; - for (var associatedElement : associations.entrySet()) { - if (!processedEntities.contains(associatedElement.getValue().getQualifiedName())) { - if (newListNeeded) { - currentList.set(new LinkedList<>()); - currentList.get().addAll(firstList); - processedEntities = localProcessEntities; - } else { - firstList.add(new AssociationIdentifier(associationName, entity.getQualifiedName())); - currentList.get().addAll(firstList); - localProcessEntities = new ArrayList<>(processedEntities); - } - processedEntities.add(associatedElement.getValue().getQualifiedName()); - newListNeeded = true; - var result = getAttachmentAssociationPath(model, associatedElement.getValue(), associatedElement.getKey(), - currentList.get(), processedEntities); - internalResultList.addAll(result); - } - } - - return internalResultList; - } - -} diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReader.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReader.java deleted file mode 100644 index 231503e1..00000000 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReader.java +++ /dev/null @@ -1,78 +0,0 @@ -/************************************************************************** - * (C) 2019-2025 SAP SE or an SAP affiliate company. All rights reserved. * - **************************************************************************/ -package com.sap.cds.feature.attachments.handler.common; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.sap.cds.CdsData; -import com.sap.cds.feature.attachments.handler.common.model.NodeTree; -import com.sap.cds.ql.CQL; -import com.sap.cds.ql.Expand; -import com.sap.cds.ql.Select; -import com.sap.cds.ql.StructuredType; -import com.sap.cds.ql.cqn.CqnFilterableStatement; -import com.sap.cds.reflect.CdsEntity; -import com.sap.cds.reflect.CdsModel; -import com.sap.cds.services.persistence.PersistenceService; - -/** - * The class {@link DefaultAttachmentsReader} is used to deep read attachments from the database - * for a determined path from the given entity to the media entity. - * The class uses the {@link AssociationCascader} to find the entity path. - *

- * The returned data is deep including the path structure to the media entity. - */ -public class DefaultAttachmentsReader implements AttachmentsReader { - - private static final Logger logger = LoggerFactory.getLogger(DefaultAttachmentsReader.class); - - private final AssociationCascader cascader; - private final PersistenceService persistence; - - public DefaultAttachmentsReader(AssociationCascader cascader, PersistenceService persistence) { - this.cascader = cascader; - this.persistence = persistence; - } - - @Override - public List readAttachments(CdsModel model, CdsEntity entity, CqnFilterableStatement statement) { - logger.debug("Start reading attachments for entity {}", entity.getQualifiedName()); - - var nodePath = cascader.findEntityPath(model, entity); - var expandList = buildExpandList(nodePath); - - Select select = !expandList.isEmpty() ? Select.from(statement.ref()).columns(expandList) - : Select.from(statement.ref()).columns(StructuredType::_all); - statement.where().ifPresent(select::where); - - var result = persistence.run(select); - var cdsData = result.listOf(CdsData.class); - logResultData(entity, cdsData); - return cdsData; - } - - private List> buildExpandList(NodeTree root) { - List> expandResultList = new ArrayList<>(); - root.getChildren().forEach(child -> expandResultList.add(buildExpandFromTree(child))); - - return expandResultList; - } - - private Expand buildExpandFromTree(NodeTree node) { - return node.getChildren().isEmpty() ? CQL.to(node.getIdentifier().associationName()).expand() : CQL.to( - node.getIdentifier().associationName()).expand(node.getChildren().stream().map(this::buildExpandFromTree).toList()); - } - - private void logResultData(CdsEntity entity, List cdsData) { - logger.debug("Read attachments for entity {}: lines {}", entity.getQualifiedName(), cdsData.size()); - if (logger.isTraceEnabled()) { - cdsData.forEach(data -> logger.trace("Read attachment data: {}", data)); - } - } - -} diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/NodeTree.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/NodeTree.java similarity index 64% rename from cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/NodeTree.java rename to cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/NodeTree.java index 7e4e1936..bdb80a17 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/model/NodeTree.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/common/NodeTree.java @@ -1,27 +1,28 @@ /************************************************************************** * (C) 2019-2025 SAP SE or an SAP affiliate company. All rights reserved. * **************************************************************************/ -package com.sap.cds.feature.attachments.handler.common.model; +package com.sap.cds.feature.attachments.handler.common; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** - * The class {@link NodeTree} is a tree data structure that holds the association identifier and its children. + * The class {@link NodeTree} is a tree data structure that holds the + * association identifier and its children. */ -public class NodeTree { +class NodeTree { private final AssociationIdentifier identifier; private final List children = new ArrayList<>(); - public NodeTree(AssociationIdentifier identifier) { + NodeTree(AssociationIdentifier identifier) { this.identifier = identifier; } - public void addPath(List path) { - var currentIdentifierOptional = path.stream().filter( - entry -> entry.fullEntityName().equals(identifier.fullEntityName())).findAny(); + void addPath(List path) { + var currentIdentifierOptional = path.stream() + .filter(entry -> entry.fullEntityName().equals(identifier.fullEntityName())).findAny(); if (currentIdentifierOptional.isEmpty()) { return; } @@ -36,9 +37,9 @@ public void addPath(List path) { } } - public NodeTree getChildOrNew(AssociationIdentifier identifier) { - var childOptional = children.stream().filter( - child -> child.identifier.fullEntityName().equals(identifier.fullEntityName())).findAny(); + private NodeTree getChildOrNew(AssociationIdentifier identifier) { + var childOptional = children.stream() + .filter(child -> child.identifier.fullEntityName().equals(identifier.fullEntityName())).findAny(); if (childOptional.isPresent()) { return childOptional.get(); } else { @@ -48,11 +49,11 @@ public NodeTree getChildOrNew(AssociationIdentifier identifier) { } } - public AssociationIdentifier getIdentifier() { + AssociationIdentifier getIdentifier() { return identifier; } - public List getChildren() { + List getChildren() { return Collections.unmodifiableList(children); } diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftActiveAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftActiveAttachmentsHandler.java index 4e8006f0..df56f3b3 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftActiveAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftActiveAttachmentsHandler.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.draftservice; +import static java.util.Objects.requireNonNull; + import com.sap.cds.feature.attachments.handler.applicationservice.helper.ThreadDataStorageSetter; import com.sap.cds.services.draft.DraftSaveEventContext; import com.sap.cds.services.draft.DraftService; @@ -16,7 +18,7 @@ public class DraftActiveAttachmentsHandler implements EventHandler { private final ThreadDataStorageSetter threadLocalSetter; public DraftActiveAttachmentsHandler(ThreadDataStorageSetter threadLocalSetter) { - this.threadLocalSetter = threadLocalSetter; + this.threadLocalSetter = requireNonNull(threadLocalSetter, "threadLocalSetter must not be null"); } @On diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandler.java index d37b7f25..f2e692aa 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandler.java @@ -3,12 +3,14 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.draftservice; +import static java.util.Objects.requireNonNull; + import com.sap.cds.CdsData; import com.sap.cds.CdsDataProcessor; import com.sap.cds.CdsDataProcessor.Filter; import com.sap.cds.CdsDataProcessor.Validator; import com.sap.cds.feature.attachments.generated.cds4j.sap.attachments.Attachments; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.MarkAsDeletedAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.ApplicationHandlerHelper; import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.ql.CQL; @@ -41,12 +43,12 @@ public class DraftCancelAttachmentsHandler implements EventHandler { && element.getName().equals(Attachments.CONTENT_ID); private final AttachmentsReader attachmentsReader; - private final ModifyAttachmentEvent deleteContentAttachmentEvent; + private final MarkAsDeletedAttachmentEvent deleteEvent; public DraftCancelAttachmentsHandler(AttachmentsReader attachmentsReader, - ModifyAttachmentEvent deleteContentAttachmentEvent) { - this.attachmentsReader = attachmentsReader; - this.deleteContentAttachmentEvent = deleteContentAttachmentEvent; + MarkAsDeletedAttachmentEvent deleteEvent) { + this.attachmentsReader = requireNonNull(attachmentsReader, "attachmentsReader must not be null"); + this.deleteEvent = requireNonNull(deleteEvent, "deleteEvent must not be null"); } @Before @@ -55,14 +57,15 @@ public void processBeforeDraftCancel(DraftCancelEventContext context) { if (isWhereEmpty(context)) { logger.debug("Processing before draft cancel event for entity {}", context.getTarget().getName()); - var activeEntity = DraftUtils.getActiveEntity(context.getTarget()); - var draftEntity = DraftUtils.getDraftEntity(context.getTarget()); + CdsEntity activeEntity = DraftUtils.getActiveEntity(context.getTarget()); + CdsEntity draftEntity = DraftUtils.getDraftEntity(context.getTarget()); - var draftAttachments = readAttachments(context, draftEntity, false); - var activeCondensedAttachments = getCondensedActiveAttachments(context, activeEntity); + List draftAttachments = readAttachments(context, draftEntity, false); + List activeCondensedAttachments = getCondensedActiveAttachments(context, activeEntity); - var validator = buildDeleteContentValidator(context, activeCondensedAttachments); - CdsDataProcessor.create().addValidator(contentIdFilter, validator).process(draftAttachments, context.getTarget()); + Validator validator = buildDeleteContentValidator(context, activeCondensedAttachments); + CdsDataProcessor.create().addValidator(contentIdFilter, validator).process(draftAttachments, + context.getTarget()); } } @@ -70,7 +73,7 @@ private Validator buildDeleteContentValidator(DraftCancelEventContext context, List activeCondensedAttachments) { return (path, element, value) -> { if (Boolean.FALSE.equals(path.target().values().get(Drafts.HAS_ACTIVE_ENTITY))) { - deleteContentAttachmentEvent.processEvent(path, null, CdsData.create(path.target().values()), context); + deleteEvent.processEvent(path, null, CdsData.create(path.target().values()), context); return; } var keys = ApplicationHandlerHelper.removeDraftKey(path.target().keys()); @@ -78,8 +81,7 @@ private Validator buildDeleteContentValidator(DraftCancelEventContext context, .filter(updatedData -> ApplicationHandlerHelper.areKeysInData(keys, updatedData)).findAny(); existingEntry.ifPresent(entry -> { if (!entry.get(Attachments.CONTENT_ID).equals(value)) { - deleteContentAttachmentEvent.processEvent(null, null, CdsData.create(path.target().values()), - context); + deleteEvent.processEvent(null, null, CdsData.create(path.target().values()), context); } }); }; diff --git a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandler.java b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandler.java index 8509f818..0a1a84e5 100644 --- a/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandler.java +++ b/cds-feature-attachments/src/main/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandler.java @@ -3,6 +3,8 @@ **************************************************************************/ package com.sap.cds.feature.attachments.handler.draftservice; +import static java.util.Objects.requireNonNull; + import com.sap.cds.CdsData; import com.sap.cds.CdsDataProcessor; import com.sap.cds.CdsDataProcessor.Converter; @@ -40,8 +42,8 @@ public class DraftPatchAttachmentsHandler implements EventHandler { private final ModifyAttachmentEventFactory eventFactory; public DraftPatchAttachmentsHandler(PersistenceService persistence, ModifyAttachmentEventFactory eventFactory) { - this.persistence = persistence; - this.eventFactory = eventFactory; + this.persistence = requireNonNull(persistence, "persistence must not be null"); + this.eventFactory = requireNonNull(eventFactory, "eventFactory must not be null"); } @Before diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/configuration/RegistrationTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/configuration/RegistrationTest.java index 966926b5..09e69232 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/configuration/RegistrationTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/configuration/RegistrationTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -70,6 +71,7 @@ void setup() { persistenceService = mock(PersistenceService.class); attachmentService = mock(AttachmentService.class); outboxService = mock(OutboxService.class); + doReturn(attachmentService).when(outboxService).outboxed(any(AttachmentService.class)); draftService = mock(DraftService.class); applicationService = mock(ApplicationService.class); serviceArgumentCaptor = ArgumentCaptor.forClass(Service.class); diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandlerTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandlerTest.java index e7d34409..a4cde6e1 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandlerTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/CreateAttachmentsHandlerTest.java @@ -29,8 +29,8 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; import com.sap.cds.feature.attachments.handler.applicationservice.helper.ThreadDataStorageReader; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEventFactory; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.reflect.CdsEntity; import com.sap.cds.services.ServiceException; diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandlerTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandlerTest.java index 7a17df07..9b795720 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandlerTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/DeleteAttachmentsHandlerTest.java @@ -21,7 +21,7 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.Roots_; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Attachment; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Attachment_; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.MarkAsDeletedAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.ql.cqn.Path; @@ -38,7 +38,7 @@ class DeleteAttachmentsHandlerTest { private DeleteAttachmentsHandler cut; private AttachmentsReader attachmentsReader; - private ModifyAttachmentEvent modifyAttachmentEvent; + private MarkAsDeletedAttachmentEvent modifyAttachmentEvent; private CdsDeleteEventContext context; @BeforeAll @@ -49,7 +49,7 @@ static void classSetup() { @BeforeEach void setup() { attachmentsReader = mock(AttachmentsReader.class); - modifyAttachmentEvent = mock(ModifyAttachmentEvent.class); + modifyAttachmentEvent = mock(MarkAsDeletedAttachmentEvent.class); cut = new DeleteAttachmentsHandler(attachmentsReader, modifyAttachmentEvent); context = mock(CdsDeleteEventContext.class); diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandlerTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandlerTest.java index 38fac8c8..101c9fc6 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandlerTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/UpdateAttachmentsHandlerTest.java @@ -29,8 +29,8 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; import com.sap.cds.feature.attachments.handler.applicationservice.helper.ThreadDataStorageReader; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEventFactory; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.feature.attachments.service.AttachmentService; diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactoryTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactoryTest.java similarity index 86% rename from cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactoryTest.java rename to cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactoryTest.java index d7c31e9c..6b122ea6 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/DefaultModifyAttachmentEventFactoryTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/ModifyAttachmentEventFactoryTest.java @@ -15,22 +15,22 @@ import com.sap.cds.CdsData; import com.sap.cds.feature.attachments.generated.cds4j.sap.attachments.Attachments; -class DefaultModifyAttachmentEventFactoryTest { +class ModifyAttachmentEventFactoryTest { - private DefaultModifyAttachmentEventFactory cut; - private ModifyAttachmentEvent createEvent; - private ModifyAttachmentEvent updateEvent; - private ModifyAttachmentEvent deleteContentEvent; - private ModifyAttachmentEvent doNothingEvent; + private ModifyAttachmentEventFactory cut; + private CreateAttachmentEvent createEvent; + private UpdateAttachmentEvent updateEvent; + private MarkAsDeletedAttachmentEvent deleteContentEvent; + private DoNothingAttachmentEvent doNothingEvent; @BeforeEach void setup() { - createEvent = mock(ModifyAttachmentEvent.class); - updateEvent = mock(ModifyAttachmentEvent.class); - deleteContentEvent = mock(ModifyAttachmentEvent.class); - doNothingEvent = mock(ModifyAttachmentEvent.class); + createEvent = mock(CreateAttachmentEvent.class); + updateEvent = mock(UpdateAttachmentEvent.class); + deleteContentEvent = mock(MarkAsDeletedAttachmentEvent.class); + doNothingEvent = mock(DoNothingAttachmentEvent.class); - cut = new DefaultModifyAttachmentEventFactory(createEvent, updateEvent, deleteContentEvent, doNothingEvent); + cut = new ModifyAttachmentEventFactory(createEvent, updateEvent, deleteContentEvent, doNothingEvent); } @Test diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEventTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEventTest.java index 4aad6f01..bec4bc70 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEventTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/applicationservice/processor/modifyevents/UpdateAttachmentEventTest.java @@ -16,14 +16,14 @@ class UpdateAttachmentEventTest { private UpdateAttachmentEvent cut; - private ModifyAttachmentEvent createEvent; - private ModifyAttachmentEvent deleteEvent; + private CreateAttachmentEvent createEvent; + private MarkAsDeletedAttachmentEvent deleteEvent; private Path path; @BeforeEach void setup() { - createEvent = mock(ModifyAttachmentEvent.class); - deleteEvent = mock(ModifyAttachmentEvent.class); + createEvent = mock(CreateAttachmentEvent.class); + deleteEvent = mock(MarkAsDeletedAttachmentEvent.class); cut = new UpdateAttachmentEvent(createEvent, deleteEvent); diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascaderTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AssociationCascaderTest.java similarity index 96% rename from cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascaderTest.java rename to cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AssociationCascaderTest.java index 4f06c7e8..540897f9 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAssociationCascaderTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AssociationCascaderTest.java @@ -14,14 +14,13 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Items_; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; -import com.sap.cds.feature.attachments.handler.common.model.NodeTree; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.services.runtime.CdsRuntime; -class DefaultAssociationCascaderTest { +class AssociationCascaderTest { private static CdsRuntime runtime; - private DefaultAssociationCascader cut; + private AssociationCascader cut; @BeforeAll static void classSetup() { @@ -30,7 +29,7 @@ static void classSetup() { @BeforeEach void setup() { - cut = new DefaultAssociationCascader(); + cut = new AssociationCascader(); } @Test diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReaderTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReaderTest.java similarity index 97% rename from cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReaderTest.java rename to cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReaderTest.java index c3d754f6..28a34e28 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/DefaultAttachmentsReaderTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/AttachmentsReaderTest.java @@ -22,8 +22,6 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.Attachment_; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Items_; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; -import com.sap.cds.feature.attachments.handler.common.model.AssociationIdentifier; -import com.sap.cds.feature.attachments.handler.common.model.NodeTree; import com.sap.cds.feature.attachments.helper.LogObserver; import com.sap.cds.ql.CQL; import com.sap.cds.ql.Delete; @@ -36,9 +34,9 @@ import ch.qos.logback.classic.Level; -class DefaultAttachmentsReaderTest { +class AttachmentsReaderTest { - private DefaultAttachmentsReader cut; + private AttachmentsReader cut; private AssociationCascader cascader; private PersistenceService persistenceService; private CdsEntity entity; @@ -52,7 +50,7 @@ void setup() { cascader = mock(AssociationCascader.class); persistenceService = mock(PersistenceService.class); - cut = new DefaultAttachmentsReader(cascader, persistenceService); + cut = new AttachmentsReader(cascader, persistenceService); entity = mock(CdsEntity.class); model = mock(CdsModel.class); diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/model/NodeTreeTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/NodeTreeTest.java similarity index 98% rename from cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/model/NodeTreeTest.java rename to cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/NodeTreeTest.java index cafe1f1e..b31ceb47 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/model/NodeTreeTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/common/NodeTreeTest.java @@ -1,4 +1,4 @@ -package com.sap.cds.feature.attachments.handler.common.model; +package com.sap.cds.feature.attachments.handler.common; import static org.assertj.core.api.Assertions.assertThat; diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandlerTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandlerTest.java index 5e47fa6c..1b47eac1 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandlerTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftCancelAttachmentsHandlerTest.java @@ -21,7 +21,7 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Attachment; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Attachment_; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.MarkAsDeletedAttachmentEvent; import com.sap.cds.feature.attachments.handler.common.AttachmentsReader; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.ql.Delete; @@ -37,7 +37,7 @@ class DraftCancelAttachmentsHandlerTest { private DraftCancelAttachmentsHandler cut; private AttachmentsReader attachmentsReader; - private ModifyAttachmentEvent deleteContentAttachmentEvent; + private MarkAsDeletedAttachmentEvent deleteContentAttachmentEvent; private DraftCancelEventContext eventContext; private ArgumentCaptor deleteArgumentCaptor; private ArgumentCaptor dataArgumentCaptor; @@ -50,7 +50,7 @@ static void classSetup() { @BeforeEach void setup() { attachmentsReader = mock(AttachmentsReader.class); - deleteContentAttachmentEvent = mock(ModifyAttachmentEvent.class); + deleteContentAttachmentEvent = mock(MarkAsDeletedAttachmentEvent.class); cut = new DraftCancelAttachmentsHandler(attachmentsReader, deleteContentAttachmentEvent); eventContext = mock(DraftCancelEventContext.class); diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandlerTest.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandlerTest.java index c452a27d..8da73648 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandlerTest.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/handler/draftservice/DraftPatchAttachmentsHandlerTest.java @@ -25,8 +25,8 @@ import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.Items; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable; import com.sap.cds.feature.attachments.generated.test.cds4j.unit.test.testservice.RootTable_; -import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEventFactory; +import com.sap.cds.feature.attachments.handler.applicationservice.processor.modifyevents.ModifyAttachmentEvent; import com.sap.cds.feature.attachments.handler.helper.RuntimeHelper; import com.sap.cds.ql.cqn.CqnSelect; import com.sap.cds.reflect.CdsEntity;