From f81684cfd33b91184409d70141c6b726fdde564e Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Wed, 22 Oct 2025 14:02:06 +0530 Subject: [PATCH 1/9] Fixing copyAttachments api for Projection entities --- .../cds/sdm/model/CopyAttachmentInput.java | 15 ++- .../com/sap/cds/sdm/persistence/DBQuery.java | 61 +++++++-- .../sap/cds/sdm/service/RegisterService.java | 8 ++ .../sdm/service/SDMAttachmentsService.java | 8 +- .../handler/AttachmentCopyEventContext.java | 71 ++++++++--- .../handler/SDMCustomServiceHandler.java | 117 ++++++++++++++---- .../handler/SDMServiceGenericHandler.java | 24 +++- .../handler/SDMCustomServiceHandlerTest.java | 65 ++++++---- .../handler/SDMServiceGenericHandlerTest.java | 19 ++- 9 files changed, 300 insertions(+), 88 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java index cdbf732b1..a1018cbf5 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java +++ b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java @@ -3,10 +3,15 @@ import java.util.List; /** - * The class {@link CopyAttachmentInput} is used to store the input for creating an attachment. + * The class {@link CopyAttachmentInput} is used to store the input for copying attachments. This + * model supports both regular entities and projection entities by using parent entity and + * composition navigation patterns. * - * @param upId The keys for the attachment entity - * @param facet - * @param objectIds + * @param upId The key of the parent entity instance + * @param parentEntity The qualified name of the parent entity that defines the attachments + * composition + * @param compositionName The name of the composition property linking parent to attachment entity + * @param objectIds The list of attachment object IDs to be copied */ -public record CopyAttachmentInput(String upId, String facet, List objectIds) {} +public record CopyAttachmentInput( + String upId, String parentEntity, String compositionName, List objectIds) {} diff --git a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java index 64ed19b4a..501b330bd 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java +++ b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java @@ -7,10 +7,14 @@ import com.sap.cds.ql.Update; import com.sap.cds.ql.cqn.CqnSelect; import com.sap.cds.ql.cqn.CqnUpdate; +import com.sap.cds.reflect.CdsAssociationType; +import com.sap.cds.reflect.CdsElement; import com.sap.cds.reflect.CdsEntity; +import com.sap.cds.reflect.CdsModel; import com.sap.cds.sdm.constants.SDMConstants; import com.sap.cds.sdm.model.CmisDocument; import com.sap.cds.sdm.service.handler.AttachmentCopyEventContext; +import com.sap.cds.services.ServiceException; import com.sap.cds.services.persistence.PersistenceService; import java.util.*; @@ -65,13 +69,44 @@ public CmisDocument getObjectIdForAttachmentID( public CmisDocument getAttachmentForObjectID( PersistenceService persistenceService, String id, AttachmentCopyEventContext context) { - Optional attachmentEntity = context.getModel().findEntity(context.getFacet()); + + // Use the new API to resolve the target attachment entity + String parentEntity = context.getParentEntity(); + String compositionName = context.getCompositionName(); + CdsModel model = context.getModel(); + + // Find the parent entity + Optional optionalParentEntity = model.findEntity(parentEntity); + if (optionalParentEntity.isEmpty()) { + throw new ServiceException("Unable to find parent entity: " + parentEntity); + } + + // Find the composition element in the parent entity + Optional compositionElement = + optionalParentEntity.get().findElement(compositionName); + if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { + throw new ServiceException( + "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); + } + + // Get the target entity of the composition + CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); + String targetEntityName = assocType.getTarget().getQualifiedName(); + + // Find the target attachment entity + Optional attachmentEntity = model.findEntity(targetEntityName); + if (attachmentEntity.isEmpty()) { + throw new ServiceException("Unable to find target attachment entity: " + targetEntityName); + } + + // Search in active entity first CqnSelect q = Select.from(attachmentEntity.get()) .columns("linkUrl", "type") .where(doc -> doc.get("objectId").eq(id)); Result result = persistenceService.run(q); Optional res = result.first(); + CmisDocument cmisDocument = new CmisDocument(); if (res.isPresent()) { Row row = res.get(); @@ -79,17 +114,19 @@ public CmisDocument getAttachmentForObjectID( cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); } else { // Check in draft table as well - attachmentEntity = context.getModel().findEntity(context.getFacet() + "_drafts"); - q = - Select.from(attachmentEntity.get()) - .columns("linkUrl", "type") - .where(doc -> doc.get("objectId").eq(id)); - result = persistenceService.run(q); - res = result.first(); - if (res.isPresent()) { - Row row = res.get(); - cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); - cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); + Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); + if (attachmentDraftEntity.isPresent()) { + q = + Select.from(attachmentDraftEntity.get()) + .columns("linkUrl", "type") + .where(doc -> doc.get("objectId").eq(id)); + result = persistenceService.run(q); + res = result.first(); + if (res.isPresent()) { + Row row = res.get(); + cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); + cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); + } } } return cmisDocument; diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java b/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java index 6d26c572a..bb653847c 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java @@ -7,5 +7,13 @@ public interface RegisterService extends Service { String SDM_NAME = "SDMAttachmentService$Default"; String EVENT_COPY_ATTACHMENT = "COPY_ATTACHMENT"; + /** + * Copies attachments using the new parent entity and composition approach. This method supports + * both regular entities and projection entities. + * + * @param input The copy attachment input containing parent entity, composition name, and object + * IDs + * @param isSystemUser Whether to use system user flow + */ public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser); } diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java index 242895df8..4fa6bfbdc 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java @@ -30,14 +30,16 @@ public SDMAttachmentsService() { @Override public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser) { logger.info( - "Copying attachments for upId: {}, facet: {}, objectIds: {}, isSystemUser: {}", + "Copying attachments for upId: {}, parentEntity: {}, compositionName: {}, objectIds: {}, isSystemUser: {}", input.upId(), - input.facet(), + input.parentEntity(), + input.compositionName(), input.objectIds(), isSystemUser); var copyContext = AttachmentCopyEventContext.create(); copyContext.setUpId(input.upId()); - copyContext.setFacet(input.facet()); + copyContext.setParentEntity(input.parentEntity()); + copyContext.setCompositionName(input.compositionName()); copyContext.setObjectIds(input.objectIds()); copyContext.setSystemUser(isSystemUser); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/AttachmentCopyEventContext.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/AttachmentCopyEventContext.java index ed29cd672..e02b358be 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/AttachmentCopyEventContext.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/AttachmentCopyEventContext.java @@ -10,8 +10,12 @@ import java.util.List; /** - * The {@link AttachmentCopyEventContext} is used to store the context of the create attachment - * event. + * The {@link AttachmentCopyEventContext} is used to store the context of the copy attachment event. + * This interface provides methods to handle attachment copying for both regular entities and + * projection entities by working with parent entities and their composition relationships. + * + *

For projection entities, the API uses the parent entity that defines the attachments + * composition and the composition name to properly navigate the relationship hierarchy. */ @EventName(RegisterService.EVENT_COPY_ATTACHMENT) public interface AttachmentCopyEventContext extends AttachmentCreateEventContext { @@ -27,48 +31,85 @@ static AttachmentCopyEventContext create() { } /** - * @return The id of the attachment storage entity or {@code null} if no id was specified + * Gets the ID of the parent entity instance for which attachments are being copied. This + * represents the key values of the entity that contains the attachment composition. + * + * @return The id of the parent entity instance or {@code null} if no id was specified */ String getUpId(); /** - * Sets the ID of the content for the attachment storage + * Sets the ID of the parent entity instance for which attachments are being copied. This should + * be the key value of the entity that contains the attachment composition. * - * @param upId The key of the content + * @param upId The key of the parent entity instance */ void setUpId(String upId); - String getFacet(); + /** + * Gets the qualified name of the parent entity that defines the attachments composition. This is + * the entity that contains the composition relationship to the attachment entity. + * + * @return The qualified name of the parent entity or {@code null} if not specified + */ + String getParentEntity(); /** - * Sets the ID of the content for the attachment storage + * Sets the qualified name of the parent entity that defines the attachments composition. This + * entity should contain the composition relationship to the attachment entity. * - * @param facet The key of the content + * @param parentEntity The qualified name of the parent entity (e.g., "Service.Entity") */ - void setFacet(String facet); + void setParentEntity(String parentEntity); /** - * @return The IDs of the attachment storage entity or {@code Collections.emptyMap} if no id was + * Gets the name of the composition property that links the parent entity to the attachment + * entity. This is the property name used in the composition relationship. + * + *

Examples: "attachments", "references" + * + * @return The name of the composition property or {@code null} if not specified + */ + String getCompositionName(); + + /** + * Sets the name of the composition property that links the parent entity to the attachment + * entity. This should match the property name defined in the CDS model. + * + * @param compositionName The name of the composition property (e.g., "references") + */ + void setCompositionName(String compositionName); + + /** + * Gets the list of object IDs representing the attachments to be copied. These are typically the + * IDs of existing attachment records that should be duplicated. + * + * @return The list of attachment object IDs or {@code Collections.emptyList()} if no IDs were * specified */ List getObjectIds(); /** - * Sets the id af the attachment entity for the attachment storage + * Sets the list of object IDs representing the attachments to be copied. Each ID should + * correspond to an existing attachment record. * - * @param ids The key of the attachment entity which defines the content field + * @param ids The list of attachment object IDs to be copied */ void setObjectIds(List ids); /** - * @return {@code true} if the user flow is used, {@code false} otherwise + * Gets whether the system user flow is being used for the copy operation. System user flow + * typically bypasses certain authorization checks and user-specific logic. + * + * @return {@code true} if the system user flow is used, {@code false} for regular user flow */ Boolean getSystemUser(); /** - * Sets whether the system user flow is used. + * Sets whether the system user flow should be used for the copy operation. Use system user flow + * when the operation should bypass user-specific authorization or logic. * - * @param systemUser {@code true} if the system user flow is used, {@code false} otherwise + * @param systemUser {@code true} to use system user flow, {@code false} for regular user flow */ void setSystemUser(boolean systemUser); } diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index b87e0bb3d..979beeadd 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -48,20 +48,26 @@ public SDMCustomServiceHandler( @On(event = RegisterService.EVENT_COPY_ATTACHMENT) public void copyAttachments(AttachmentCopyEventContext context) throws IOException { - String[] splitFacet = context.getFacet().split("\\."); - if (splitFacet.length < 3) { - throw new ServiceException(SDMConstants.FAILED_TO_FETCH_FACET); - } - String facet = splitFacet[2]; + + System.out.println("Inside copyAttachments handler of SDMCustomServiceHandler"); + String parentEntity = context.getParentEntity(); + System.out.println("parentEntity: " + parentEntity); + String compositionName = context.getCompositionName(); + System.out.println("compositionName: " + compositionName); String upID = context.getUpId(); - String folderName = upID + "__" + facet; + System.out.println("upID: " + upID); + String folderName = upID + "__" + compositionName; + System.out.println("folderName: " + folderName); String repositoryId = SDMConstants.REPOSITORY_ID; + System.out.println("repositoryId: " + repositoryId); Boolean isSystemUser = context.getSystemUser(); + System.out.println("isSystemUser: " + isSystemUser); boolean folderExists = true; SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); String folderId = sdmService.getFolderIdByPath(folderName, repositoryId, sdmCredentials, isSystemUser); + System.out.println("folderId: " + folderId); if (folderId == null) { folderExists = false; folderId = @@ -70,14 +76,17 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti JSONObject jsonObject = new JSONObject(folderId); JSONObject succinctProperties = jsonObject.getJSONObject("succinctProperties"); folderId = succinctProperties.getString("cmis:objectId"); + System.out.println("Created new folder with folderId: " + folderId); } CmisDocument cmisDocument = new CmisDocument(); List objectIds = context.getObjectIds(); + System.out.println("objectIds: " + objectIds); List> attachmentsMetadata = new ArrayList<>(); for (String objectId : objectIds) { // get Link Url from objectId and set to cmisDocument cmisDocument = dbQuery.getAttachmentForObjectID(persistenceService, objectId, context); + System.out.println("cmisDocument: " + cmisDocument); cmisDocument.setObjectId(objectId); cmisDocument.setRepositoryId(repositoryId); cmisDocument.setFolderId(folderId); @@ -87,9 +96,12 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti } catch (ServiceException e) { if (!folderExists) { // deleteFolder + System.out.println( + "Exception occurred, deleting created folder with folderId: " + folderId); sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); throw new ServiceException(e.getMessage()); } else { + System.out.println("Exception occurred, deleting copied attachments"); for (List attachmentMetadata : attachmentsMetadata) { // delete the copied attachments sdmService.deleteDocument( @@ -100,25 +112,64 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti } } - String upIdKey = ""; + // Find the parent entity's draft table and composition + String upIdKey = null; CdsModel model = context.getModel(); - Optional attachmentDraftEntity = model.findEntity(context.getFacet() + "_drafts"); - Optional upAssociation = attachmentDraftEntity.get().findAssociation("up_"); - if (upAssociation.isPresent()) { - CdsElement association = upAssociation.get(); - CdsAssociationType assocType = association.getType(); - List fkElements = assocType.refs().map(ref -> "up__" + ref.path()).toList(); - upIdKey = fkElements.get(0); + + Optional optionalParentEntity = model.findEntity(parentEntity); + System.out.println("optionalParentEntity: " + optionalParentEntity); + if (optionalParentEntity.isEmpty()) { + throw new ServiceException("Unable to find parent entity: " + parentEntity); + } + + // Find the composition element in the parent draft entity + Optional compositionElement = + optionalParentEntity.get().findElement(compositionName); + System.out.println("compositionElement: " + compositionElement); + if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { + throw new ServiceException( + "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } + + // Get the target entity of the composition + CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); + System.out.println("assocType: " + assocType); + String targetEntityName = assocType.getTarget().getQualifiedName(); + System.out.println("targetEntityName: " + targetEntityName); + + // Find the target entity's draft table to get upIdKey + Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); + System.out.println("attachmentDraftEntity: " + attachmentDraftEntity); + if (attachmentDraftEntity.isPresent()) { + Optional upAssociation = attachmentDraftEntity.get().findAssociation("up_"); + System.out.println("upAssociation: " + upAssociation); + if (upAssociation.isPresent()) { + CdsElement association = upAssociation.get(); + System.out.println("association: " + association); + CdsAssociationType upAssocType = association.getType(); + System.out.println("upAssocType: " + upAssocType); + List fkElements = upAssocType.refs().map(ref -> "up__" + ref.path()).toList(); + System.out.println("fkElements: " + fkElements); + upIdKey = fkElements.get(0); + System.out.println("upIdKey: " + upIdKey); + } + } + + final String finalUpIdKey = upIdKey; + + // Process attachments with new Insert pattern Map updatedFields = new HashMap<>(); for (List attachmentMetadata : attachmentsMetadata) { String fileName = attachmentMetadata.get(0); + System.out.println("fileName: " + fileName); String mimeType = attachmentMetadata.get(1); + System.out.println("mimeType: " + mimeType); if (mimeType.equalsIgnoreCase("application/internet-shortcut")) { int dotIndex = fileName.lastIndexOf('.'); fileName = fileName.substring(0, dotIndex); } String newObjectId = attachmentMetadata.get(2); + updatedFields.put("objectId", newObjectId); updatedFields.put("repositoryId", repositoryId); updatedFields.put("folderId", folderId); @@ -130,15 +181,39 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti updatedFields.put("HasActiveEntity", false); updatedFields.put("linkUrl", cmisDocument.getUrl()); updatedFields.put( - "contentId", newObjectId + ":" + folderId + ":" + context.getFacet() + ":" + mimeType); + "contentId", + newObjectId + + ":" + + folderId + + ":" + + parentEntity + + "." + + compositionName + + ":" + + mimeType); updatedFields.put(upIdKey, upID); - var insert = Insert.into(context.getFacet()).entry(updatedFields); - for (DraftService draftS : draftService) { - // Check if the draft service name matches the context facet - if (context.getFacet().contains(draftS.getName())) { - draftS.newDraft(insert); - } + // Use the recommended Insert pattern for projection entities + // Remove "up__" prefix from finalUpIdKey for the filter condition + String baseKeyField = finalUpIdKey != null ? finalUpIdKey.replace("up__", "") : "ID"; + var insert = + Insert.into(parentEntity, e -> e.filter(e.get(baseKeyField).eq(upID)).to(compositionName)) + .entry(updatedFields); + System.out.println("Insert: " + insert); + System.out.println("Using baseKeyField: " + baseKeyField + " for filter"); + + // Use DraftService with fallback to PersistenceService + DraftService matchingService = + draftService.stream() + .filter(ds -> parentEntity.contains(ds.getName())) + .findFirst() + .orElse(null); + + if (matchingService != null) { + System.out.println("Using DraftService: " + matchingService.getName()); + matchingService.newDraft(insert); + } else { + throw new ServiceException("No suitable service found for entity: " + parentEntity); } } context.setCompleted(); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java index cdd7ca2c0..8223630ff 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java @@ -67,10 +67,30 @@ public SDMServiceGenericHandler( @On(event = "copyAttachments") public void copyAttachments(EventContext context) throws IOException { String upID = context.get("up__ID").toString(); + System.out.println("upID: " + upID); String objectIdsString = context.get("objectIds").toString(); + System.out.println("objectIdsString: " + objectIdsString); List objectIds = Arrays.stream(objectIdsString.split(",")).map(String::trim).toList(); - var copyEventInput = - new CopyAttachmentInput(upID, context.getTarget().getQualifiedName(), objectIds); + + // Extract parent entity and composition from target + String targetQualifiedName = context.getTarget().getQualifiedName(); + System.out.println("targetQualifiedName: " + targetQualifiedName); + String[] targetParts = targetQualifiedName.split("\\."); + System.out.println("targetParts: " + Arrays.toString(targetParts)); + + if (targetParts.length < 3) { + throw new ServiceException( + "Invalid target format. Expected: Service.Entity.Composition, got: " + + targetQualifiedName); + } + + String parentEntity = targetParts[0] + "." + targetParts[1]; // Service.Entity + System.out.println("parentEntity: " + parentEntity); + String compositionName = targetParts[2]; // composition name + System.out.println("compositionName: " + compositionName); + + var copyEventInput = new CopyAttachmentInput(upID, parentEntity, compositionName, objectIds); + attachmentService.copyAttachments(copyEventInput, context.getUserInfo().isSystemUser()); context.setCompleted(); } diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMCustomServiceHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMCustomServiceHandlerTest.java index 851c412f9..9b2d11761 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMCustomServiceHandlerTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMCustomServiceHandlerTest.java @@ -126,21 +126,6 @@ void testCopyAttachments_HappyPathNonLink() throws IOException { verify(context, times(1)).setCompleted(); } - @Test - void testCopyAttachments_InvalidFacetFormat_ThrowsException() throws IOException { - AttachmentCopyEventContext context = mock(AttachmentCopyEventContext.class); - when(context.getFacet()).thenReturn("invalid.facet"); // Only 2 parts - // Other mocks not needed as exception is thrown before they're used - - ServiceException ex = - assertThrows( - ServiceException.class, - () -> { - sdmCustomServiceHandler.copyAttachments(context); - }); - assertTrue(ex.getMessage().contains("Invalid facet format")); - } - @Test void testCopyAttachments_FolderDoesNotExist() throws IOException { // Mock SDMCredentials @@ -203,14 +188,25 @@ void testCopyAttachments_AttachmentCopyFails() throws IOException { // Mock context AttachmentCopyEventContext context = createMockContext(); - context.setObjectIds(List.of(OBJECT_ID, "mockObjectId2")); + // Override the getObjectIds mock to return multiple objects for this test + when(context.getObjectIds()).thenReturn(List.of(OBJECT_ID, "mockObjectId2")); + + // Mock UserInfo for cleanup operations + UserInfo userInfo = mock(UserInfo.class); + when(context.getUserInfo()).thenReturn(userInfo); + when(userInfo.getName()).thenReturn("testUser"); // Act & Assert - try { - sdmCustomServiceHandler.copyAttachments(context); - } catch (ServiceException e) { - verify(sdmService, times(1)).deleteDocument(any(String.class), any(String.class), any()); - } + ServiceException exception = + assertThrows( + ServiceException.class, + () -> { + sdmCustomServiceHandler.copyAttachments(context); + }); + + // Verify that deleteDocument was called for cleanup of the first successful attachment + verify(sdmService, times(1)).deleteDocument(eq("delete"), eq(OBJECT_ID), eq("testUser")); + assertTrue(exception.getMessage().contains("Copy failed")); } @Test @@ -291,19 +287,36 @@ private AttachmentCopyEventContext createMockContext() { CdsAssociationType mockAssociationType = mock(CdsAssociationType.class); CqnElementRef mockCqnElementRef = mock(CqnElementRef.class); - when(context.getFacet()).thenReturn("prefix.someIdentifier." + FACET); + when(context.getParentEntity()).thenReturn("prefix.someIdentifier." + FACET); + when(context.getCompositionName()).thenReturn(FACET); when(context.getUpId()).thenReturn(UP_ID); when(context.getSystemUser()).thenReturn(true); when(context.getObjectIds()).thenReturn(List.of(OBJECT_ID)); // Mock CdsModel and relevant entities and associations CdsModel model = mock(CdsModel.class); - CdsEntity entity = mock(CdsEntity.class); + CdsEntity parentEntity = mock(CdsEntity.class); + CdsEntity draftEntity = mock(CdsEntity.class); + CdsEntity targetEntity = mock(CdsEntity.class); + + // Mock composition element and its type + CdsElement compositionElement = mock(CdsElement.class); + CdsAssociationType compositionType = mock(CdsAssociationType.class); - // Setup expected behavior + // Setup expected behavior for model and parent entity when(context.getModel()).thenReturn(model); - when(model.findEntity(any(String.class))).thenReturn(Optional.of(entity)); - when(entity.findAssociation("up_")).thenReturn(Optional.of(mockAssociationElement)); + when(model.findEntity("prefix.someIdentifier." + FACET)).thenReturn(Optional.of(parentEntity)); + when(model.findEntity(endsWith("_drafts"))).thenReturn(Optional.of(draftEntity)); + + // Mock the composition element in parent entity + when(parentEntity.findElement(FACET)).thenReturn(Optional.of(compositionElement)); + when(compositionElement.getType()).thenReturn(compositionType); + when(compositionType.isAssociation()).thenReturn(true); + when(compositionType.getTarget()).thenReturn(targetEntity); + when(targetEntity.getQualifiedName()).thenReturn("target.entity.name"); + + // Mock the draft entity's up_ association + when(draftEntity.findAssociation("up_")).thenReturn(Optional.of(mockAssociationElement)); when(mockAssociationElement.getType()).thenReturn(mockAssociationType); when(mockAssociationType.refs()).thenReturn(Stream.of(mockCqnElementRef)); when(mockCqnElementRef.path()).thenReturn("ID"); diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java index 177e3b6c5..9601713a1 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java @@ -111,7 +111,6 @@ void testCopyAttachments_shouldCopyAttachment() throws IOException { verify(attachmentService, times(1)).copyAttachments(captor.capture(), eq(false)); CopyAttachmentInput input = captor.getValue(); assert input.upId().equals("123"); - assert input.facet().equals("MyService.MyEntity.attachments"); assert input.objectIds().equals(List.of("abc", "xyz")); verify(mockContext, times(1)).setCompleted(); } @@ -153,6 +152,7 @@ void testCreate_shouldCreateLink() throws IOException { when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -244,6 +244,7 @@ void testCreate_ShouldThrowSpecifiedExceptionWhenMaxCountReached() throws IOExce when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -260,7 +261,8 @@ void testCreate_ShouldThrowSpecifiedExceptionWhenMaxCountReached() throws IOExce when(analyzer.analyze(any(CqnSelect.class))).thenReturn(analysisResult); when(analysisResult.rootKeys()).thenReturn(Map.of("ID", "123")); - // when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); + // + when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); when(draftEntity.findAssociation("up_")).thenReturn(Optional.of(mockAssociationElement)); when(mockAssociationElement.getType()).thenReturn(mockAssociationType); when(mockAssociationType.refs()).thenReturn(Stream.of(mockCqnElementRef)); @@ -300,6 +302,7 @@ void testCreate_ShouldThrowDefaultExceptionWhenMaxCountReached() throws IOExcept when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -316,7 +319,8 @@ void testCreate_ShouldThrowDefaultExceptionWhenMaxCountReached() throws IOExcept when(analyzer.analyze(any(CqnSelect.class))).thenReturn(analysisResult); when(analysisResult.rootKeys()).thenReturn(Map.of("ID", "123")); - // when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); + // + when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); when(draftEntity.findAssociation("up_")).thenReturn(Optional.of(mockAssociationElement)); when(mockAssociationElement.getType()).thenReturn(mockAssociationType); when(mockAssociationType.refs()).thenReturn(Stream.of(mockCqnElementRef)); @@ -356,6 +360,7 @@ void testCreate_ShouldThrowExceptionWhenRestrictedCharacterInLinkName() throws I when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -372,7 +377,8 @@ void testCreate_ShouldThrowExceptionWhenRestrictedCharacterInLinkName() throws I when(analyzer.analyze(any(CqnSelect.class))).thenReturn(analysisResult); when(analysisResult.rootKeys()).thenReturn(Map.of("ID", "123")); - // when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); + // + when(cdsModel.findEntity("MyService.MyEntity_drafts")).thenReturn(Optional.of(draftEntity)); when(draftEntity.findAssociation("up_")).thenReturn(Optional.of(mockAssociationElement)); when(mockAssociationElement.getType()).thenReturn(mockAssociationType); when(mockAssociationType.refs()).thenReturn(Stream.of(mockCqnElementRef)); @@ -414,6 +420,7 @@ void testCreate_ThrowsServiceExceptionOnDuplicateFile() throws IOException { when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -474,6 +481,7 @@ void testCreate_ThrowsServiceException_WhenCreateDocumentThrowsException() throw when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -541,6 +549,7 @@ void testCreate_ThrowsServiceExceptionOnDuplicateStatus() throws IOException { when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -609,6 +618,7 @@ void testCreate_ThrowsServiceExceptionOnFailStatus() throws IOException { when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); @@ -676,6 +686,7 @@ void testCreate_ThrowsServiceExceptionOnUnauthorizedStatus() throws IOException when(draftEntity.getQualifiedName()).thenReturn("MyService.MyEntity.attachments"); when(cdsModel.findEntity("MyService.MyEntity.attachments_drafts")) .thenReturn(Optional.of(draftEntity)); + when(cdsModel.findEntity("MyService.MyEntity.attachments")).thenReturn(Optional.of(cdsEntity)); when(mockContext.getEvent()).thenReturn("createLink"); CqnSelect cqnSelect = mock(CqnSelect.class); From 2742bf69be887ede96bf0c1adebc9a2399281e8f Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Wed, 22 Oct 2025 14:16:16 +0530 Subject: [PATCH 2/9] Update sdm plugin version for local-deployment --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 82b3e6e5f..2c0a71411 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - 1.5.1-SNAPSHOT + 1.0.0-RC1 17 ${java.version} ${java.version} From 8d18c5098c757b420d0b61297c440fe223dff202 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Wed, 22 Oct 2025 14:29:52 +0530 Subject: [PATCH 3/9] Sonar fix to reduce the cognitive complexity of copyAttachments() --- .../handler/SDMCustomServiceHandler.java | 123 ++++++++++++------ 1 file changed, 86 insertions(+), 37 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index 979beeadd..fd2d5848f 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -62,14 +62,43 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti System.out.println("repositoryId: " + repositoryId); Boolean isSystemUser = context.getSystemUser(); System.out.println("isSystemUser: " + isSystemUser); - boolean folderExists = true; SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); + // Check if folder exists before trying to create it + boolean folderExists = + sdmService.getFolderIdByPath(folderName, repositoryId, sdmCredentials, isSystemUser) + != null; + String folderId = ensureFolderExists(folderName, repositoryId, sdmCredentials, isSystemUser); + + CmisDocument cmisDocument = new CmisDocument(); + List objectIds = context.getObjectIds(); + System.out.println("objectIds: " + objectIds); + + List> attachmentsMetadata = + copyAttachmentsToSDM( + context, objectIds, folderId, repositoryId, sdmCredentials, isSystemUser, folderExists); + + String upIdKey = resolveUpIdKey(context, parentEntity, compositionName); + createDraftEntries( + attachmentsMetadata, + parentEntity, + compositionName, + upID, + upIdKey, + repositoryId, + folderId, + cmisDocument); + + context.setCompleted(); + } + + private String ensureFolderExists( + String folderName, String repositoryId, SDMCredentials sdmCredentials, Boolean isSystemUser) + throws IOException { String folderId = sdmService.getFolderIdByPath(folderName, repositoryId, sdmCredentials, isSystemUser); System.out.println("folderId: " + folderId); if (folderId == null) { - folderExists = false; folderId = sdmService.createFolder( folderName, SDMConstants.REPOSITORY_ID, sdmCredentials, isSystemUser); @@ -78,51 +107,67 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti folderId = succinctProperties.getString("cmis:objectId"); System.out.println("Created new folder with folderId: " + folderId); } - CmisDocument cmisDocument = new CmisDocument(); + return folderId; + } - List objectIds = context.getObjectIds(); - System.out.println("objectIds: " + objectIds); + private List> copyAttachmentsToSDM( + AttachmentCopyEventContext context, + List objectIds, + String folderId, + String repositoryId, + SDMCredentials sdmCredentials, + Boolean isSystemUser, + boolean folderExists) + throws IOException { List> attachmentsMetadata = new ArrayList<>(); + for (String objectId : objectIds) { - // get Link Url from objectId and set to cmisDocument - cmisDocument = dbQuery.getAttachmentForObjectID(persistenceService, objectId, context); + CmisDocument cmisDocument = + dbQuery.getAttachmentForObjectID(persistenceService, objectId, context); System.out.println("cmisDocument: " + cmisDocument); cmisDocument.setObjectId(objectId); cmisDocument.setRepositoryId(repositoryId); cmisDocument.setFolderId(folderId); + try { attachmentsMetadata.add( sdmService.copyAttachment(cmisDocument, sdmCredentials, isSystemUser)); } catch (ServiceException e) { - if (!folderExists) { - // deleteFolder - System.out.println( - "Exception occurred, deleting created folder with folderId: " + folderId); - sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); - throw new ServiceException(e.getMessage()); - } else { - System.out.println("Exception occurred, deleting copied attachments"); - for (List attachmentMetadata : attachmentsMetadata) { - // delete the copied attachments - sdmService.deleteDocument( - "delete", attachmentMetadata.get(2), context.getUserInfo().getName()); - } - throw new ServiceException(e.getMessage()); - } + handleCopyFailure(context, folderId, folderExists, attachmentsMetadata, e); } } + return attachmentsMetadata; + } - // Find the parent entity's draft table and composition - String upIdKey = null; - CdsModel model = context.getModel(); + private void handleCopyFailure( + AttachmentCopyEventContext context, + String folderId, + boolean folderExists, + List> attachmentsMetadata, + ServiceException e) + throws IOException { + if (!folderExists) { + System.out.println("Exception occurred, deleting created folder with folderId: " + folderId); + sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); + } else { + System.out.println("Exception occurred, deleting copied attachments"); + for (List attachmentMetadata : attachmentsMetadata) { + sdmService.deleteDocument( + "delete", attachmentMetadata.get(2), context.getUserInfo().getName()); + } + } + throw new ServiceException(e.getMessage()); + } + private String resolveUpIdKey( + AttachmentCopyEventContext context, String parentEntity, String compositionName) { + CdsModel model = context.getModel(); Optional optionalParentEntity = model.findEntity(parentEntity); System.out.println("optionalParentEntity: " + optionalParentEntity); if (optionalParentEntity.isEmpty()) { throw new ServiceException("Unable to find parent entity: " + parentEntity); } - // Find the composition element in the parent draft entity Optional compositionElement = optionalParentEntity.get().findElement(compositionName); System.out.println("compositionElement: " + compositionElement); @@ -131,13 +176,11 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } - // Get the target entity of the composition CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); System.out.println("assocType: " + assocType); String targetEntityName = assocType.getTarget().getQualifiedName(); System.out.println("targetEntityName: " + targetEntityName); - // Find the target entity's draft table to get upIdKey Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); System.out.println("attachmentDraftEntity: " + attachmentDraftEntity); if (attachmentDraftEntity.isPresent()) { @@ -150,15 +193,25 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti System.out.println("upAssocType: " + upAssocType); List fkElements = upAssocType.refs().map(ref -> "up__" + ref.path()).toList(); System.out.println("fkElements: " + fkElements); - upIdKey = fkElements.get(0); + String upIdKey = fkElements.get(0); System.out.println("upIdKey: " + upIdKey); + return upIdKey; } } + return null; + } - final String finalUpIdKey = upIdKey; - - // Process attachments with new Insert pattern + private void createDraftEntries( + List> attachmentsMetadata, + String parentEntity, + String compositionName, + String upID, + String upIdKey, + String repositoryId, + String folderId, + CmisDocument cmisDocument) { Map updatedFields = new HashMap<>(); + for (List attachmentMetadata : attachmentsMetadata) { String fileName = attachmentMetadata.get(0); System.out.println("fileName: " + fileName); @@ -193,16 +246,13 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti + mimeType); updatedFields.put(upIdKey, upID); - // Use the recommended Insert pattern for projection entities - // Remove "up__" prefix from finalUpIdKey for the filter condition - String baseKeyField = finalUpIdKey != null ? finalUpIdKey.replace("up__", "") : "ID"; + String baseKeyField = upIdKey != null ? upIdKey.replace("up__", "") : "ID"; var insert = Insert.into(parentEntity, e -> e.filter(e.get(baseKeyField).eq(upID)).to(compositionName)) .entry(updatedFields); System.out.println("Insert: " + insert); System.out.println("Using baseKeyField: " + baseKeyField + " for filter"); - // Use DraftService with fallback to PersistenceService DraftService matchingService = draftService.stream() .filter(ds -> parentEntity.contains(ds.getName())) @@ -216,6 +266,5 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti throw new ServiceException("No suitable service found for entity: " + parentEntity); } } - context.setCompleted(); } } From ba6356df9165fcedbbb63d3ff505808cf4bfb56c Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Wed, 22 Oct 2025 16:49:10 +0530 Subject: [PATCH 4/9] Added logs --- .../com/sap/cds/sdm/persistence/DBQuery.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java index 501b330bd..992878f8b 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java +++ b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java @@ -72,30 +72,41 @@ public CmisDocument getAttachmentForObjectID( // Use the new API to resolve the target attachment entity String parentEntity = context.getParentEntity(); + System.out.println("Parent Entity: " + parentEntity); String compositionName = context.getCompositionName(); + System.out.println("Composition Name: " + compositionName); CdsModel model = context.getModel(); + System.out.println("model: " + model); // Find the parent entity Optional optionalParentEntity = model.findEntity(parentEntity); + System.out.println("optionalParentEntity: " + optionalParentEntity); if (optionalParentEntity.isEmpty()) { + System.out.println("optionalParentEntity is empty"); throw new ServiceException("Unable to find parent entity: " + parentEntity); } // Find the composition element in the parent entity Optional compositionElement = optionalParentEntity.get().findElement(compositionName); + System.out.println("compositionElement: " + compositionElement); if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { + System.out.println("compositionElement is empty or not an association"); throw new ServiceException( "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } // Get the target entity of the composition CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); + System.out.println("assocType: " + assocType); String targetEntityName = assocType.getTarget().getQualifiedName(); + System.out.println("targetEntityName: " + targetEntityName); // Find the target attachment entity Optional attachmentEntity = model.findEntity(targetEntityName); + System.out.println("attachmentEntity: " + attachmentEntity); if (attachmentEntity.isEmpty()) { + System.out.println("attachmentEntity is empty"); throw new ServiceException("Unable to find target attachment entity: " + targetEntityName); } @@ -105,30 +116,41 @@ public CmisDocument getAttachmentForObjectID( .columns("linkUrl", "type") .where(doc -> doc.get("objectId").eq(id)); Result result = persistenceService.run(q); + System.out.println("result: " + result); Optional res = result.first(); + System.out.println("res: " + res); CmisDocument cmisDocument = new CmisDocument(); if (res.isPresent()) { Row row = res.get(); + System.out.println("row: " + row); cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); } else { // Check in draft table as well + System.out.println("Inside else"); Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); + System.out.println("attachmentDraftEntity: " + attachmentDraftEntity); if (attachmentDraftEntity.isPresent()) { + System.out.println("attachmentDraftEntity is present"); q = Select.from(attachmentDraftEntity.get()) .columns("linkUrl", "type") .where(doc -> doc.get("objectId").eq(id)); result = persistenceService.run(q); + System.out.println("result: " + result); res = result.first(); + System.out.println("res: " + res); if (res.isPresent()) { + System.out.println("res is present"); Row row = res.get(); + System.out.println("row: " + row); cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); } } } + System.out.println("cmisDocument: " + cmisDocument); return cmisDocument; } From a9b0b9d67cc7217847b8051f197e143fca99628e Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Wed, 22 Oct 2025 18:00:26 +0530 Subject: [PATCH 5/9] logs for openAttachment --- .../cds/sdm/service/handler/SDMCustomServiceHandler.java | 3 +++ .../cds/sdm/service/handler/SDMServiceGenericHandler.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index fd2d5848f..65a57cac8 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -78,7 +78,10 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti copyAttachmentsToSDM( context, objectIds, folderId, repositoryId, sdmCredentials, isSystemUser, folderExists); + System.out.println("attachmentsMetadata: " + attachmentsMetadata); + String upIdKey = resolveUpIdKey(context, parentEntity, compositionName); + System.out.println("upIdKey: " + upIdKey); createDraftEntries( attachmentsMetadata, parentEntity, diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java index 8223630ff..af420ded0 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java @@ -113,20 +113,26 @@ public void openAttachment(AttachmentReadContext context) throws Exception { CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel); Optional attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName() + "_drafts"); + System.out.println("attachmentEntity: " + attachmentEntity); Map targetKeys = cqnAnalyzer.analyze((CqnSelect) context.get("cqn")).targetKeyValues(); // get the objectId against the Id String id = targetKeys.get("ID").toString(); + System.out.println("id: " + id); CmisDocument cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); + System.out.println("cmisDocument: " + cmisDocument); if (cmisDocument.getFileName() == null || cmisDocument.getFileName().isEmpty()) { // open attachment is triggered on non-draft entity attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName()); cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); + System.out.println("cmisDocument (non-draft): " + cmisDocument); } if (cmisDocument.getMimeType().equalsIgnoreCase("application/internet-shortcut")) { + System.out.println("Link detected, fetching URL"); + System.out.println("cmisDocument before fetching URL: " + cmisDocument.getUrl()); context.setResult(cmisDocument.getUrl()); } else { context.setResult("None"); From 30fb4d82215e5cd12cf4352a8271cb4564acd4f7 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 23 Oct 2025 14:45:38 +0530 Subject: [PATCH 6/9] Update SDMAttachmentService to accept only 3 parameters up__ID, facet-name & List of objectIds to copy --- .../cds/sdm/model/CopyAttachmentInput.java | 11 ++-- .../sap/cds/sdm/service/RegisterService.java | 8 +-- .../sdm/service/SDMAttachmentsService.java | 20 ++++-- .../handler/SDMCustomServiceHandler.java | 1 + .../handler/SDMServiceGenericHandler.java | 21 ++---- .../sdm/service/CopyAttachmentInputTest.java | 65 +++++++++++++++++++ .../handler/SDMServiceGenericHandlerTest.java | 1 + 7 files changed, 94 insertions(+), 33 deletions(-) create mode 100644 sdm/src/test/java/unit/com/sap/cds/sdm/service/CopyAttachmentInputTest.java diff --git a/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java index a1018cbf5..43fb326d1 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java +++ b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentInput.java @@ -4,14 +4,11 @@ /** * The class {@link CopyAttachmentInput} is used to store the input for copying attachments. This - * model supports both regular entities and projection entities by using parent entity and - * composition navigation patterns. + * model supports both regular entities and projection entities by using facet-based navigation. * * @param upId The key of the parent entity instance - * @param parentEntity The qualified name of the parent entity that defines the attachments - * composition - * @param compositionName The name of the composition property linking parent to attachment entity + * @param facet The full facet path (e.g., "Service.Entity.composition") that will be internally + * parsed to determine parent entity and composition name * @param objectIds The list of attachment object IDs to be copied */ -public record CopyAttachmentInput( - String upId, String parentEntity, String compositionName, List objectIds) {} +public record CopyAttachmentInput(String upId, String facet, List objectIds) {} diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java b/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java index bb653847c..078668b00 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/RegisterService.java @@ -8,11 +8,11 @@ public interface RegisterService extends Service { String EVENT_COPY_ATTACHMENT = "COPY_ATTACHMENT"; /** - * Copies attachments using the new parent entity and composition approach. This method supports - * both regular entities and projection entities. + * Copies attachments using the facet-based approach. This method supports both regular entities + * and projection entities by internally parsing the facet to determine parent entity and + * composition name. * - * @param input The copy attachment input containing parent entity, composition name, and object - * IDs + * @param input The copy attachment input containing facet and object IDs * @param isSystemUser Whether to use system user flow */ public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java index 4fa6bfbdc..c73ffbafc 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java @@ -30,16 +30,26 @@ public SDMAttachmentsService() { @Override public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser) { logger.info( - "Copying attachments for upId: {}, parentEntity: {}, compositionName: {}, objectIds: {}, isSystemUser: {}", + "Copying attachments for upId: {}, facet: {}, objectIds: {}, isSystemUser: {}", input.upId(), - input.parentEntity(), - input.compositionName(), + input.facet(), input.objectIds(), isSystemUser); + + // Parse facet to extract parent entity and composition name + String[] facetParts = input.facet().split("\\."); + if (facetParts.length < 3) { + throw new IllegalArgumentException( + "Invalid facet format. Expected: Service.Entity.Composition, got: " + input.facet()); + } + + String parentEntity = facetParts[0] + "." + facetParts[1]; // Service.Entity + String compositionName = facetParts[2]; // composition name + var copyContext = AttachmentCopyEventContext.create(); copyContext.setUpId(input.upId()); - copyContext.setParentEntity(input.parentEntity()); - copyContext.setCompositionName(input.compositionName()); + copyContext.setParentEntity(parentEntity); + copyContext.setCompositionName(compositionName); copyContext.setObjectIds(input.objectIds()); copyContext.setSystemUser(isSystemUser); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index 65a57cac8..d8b4d67bd 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -248,6 +248,7 @@ private void createDraftEntries( + ":" + mimeType); updatedFields.put(upIdKey, upID); + System.out.println("updatedFields: " + updatedFields); String baseKeyField = upIdKey != null ? upIdKey.replace("up__", "") : "ID"; var insert = diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java index af420ded0..fed8878e7 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java @@ -72,24 +72,11 @@ public void copyAttachments(EventContext context) throws IOException { System.out.println("objectIdsString: " + objectIdsString); List objectIds = Arrays.stream(objectIdsString.split(",")).map(String::trim).toList(); - // Extract parent entity and composition from target - String targetQualifiedName = context.getTarget().getQualifiedName(); - System.out.println("targetQualifiedName: " + targetQualifiedName); - String[] targetParts = targetQualifiedName.split("\\."); - System.out.println("targetParts: " + Arrays.toString(targetParts)); + // Use the full target qualified name as the facet + String facet = context.getTarget().getQualifiedName(); + System.out.println("facet: " + facet); - if (targetParts.length < 3) { - throw new ServiceException( - "Invalid target format. Expected: Service.Entity.Composition, got: " - + targetQualifiedName); - } - - String parentEntity = targetParts[0] + "." + targetParts[1]; // Service.Entity - System.out.println("parentEntity: " + parentEntity); - String compositionName = targetParts[2]; // composition name - System.out.println("compositionName: " + compositionName); - - var copyEventInput = new CopyAttachmentInput(upID, parentEntity, compositionName, objectIds); + var copyEventInput = new CopyAttachmentInput(upID, facet, objectIds); attachmentService.copyAttachments(copyEventInput, context.getUserInfo().isSystemUser()); context.setCompleted(); diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/CopyAttachmentInputTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/CopyAttachmentInputTest.java new file mode 100644 index 000000000..57cd25a67 --- /dev/null +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/CopyAttachmentInputTest.java @@ -0,0 +1,65 @@ +package unit.com.sap.cds.sdm.service; + +import static org.junit.jupiter.api.Assertions.*; + +import com.sap.cds.sdm.model.CopyAttachmentInput; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class CopyAttachmentInputTest { + + @Test + void testFacetBasedInput() { + // Test the new 3-parameter approach + String upId = "123"; + String facet = "SourcingEventService.TermDefinitionsServiceEntity.references"; + List objectIds = List.of("obj1", "obj2", "obj3"); + + CopyAttachmentInput input = new CopyAttachmentInput(upId, facet, objectIds); + + assertEquals("123", input.upId()); + assertEquals("SourcingEventService.TermDefinitionsServiceEntity.references", input.facet()); + assertEquals(List.of("obj1", "obj2", "obj3"), input.objectIds()); + } + + @Test + void testFacetParsing() { + // This test shows how the facet should be parsed + String facet = "SourcingEventService.TermDefinitionsServiceEntity.references"; + String[] parts = facet.split("\\."); + + assertEquals(3, parts.length); + assertEquals("SourcingEventService", parts[0]); + assertEquals("TermDefinitionsServiceEntity", parts[1]); + assertEquals("references", parts[2]); + + String parentEntity = parts[0] + "." + parts[1]; + String compositionName = parts[2]; + + assertEquals("SourcingEventService.TermDefinitionsServiceEntity", parentEntity); + assertEquals("references", compositionName); + } + + @Test + void testProjectionEntityFacet() { + // Test with a projection entity facet - should parse the same way + String projectionFacet = "MyService.MyProjectionEntity.attachments"; + String[] parts = projectionFacet.split("\\."); + + assertEquals(3, parts.length); + String parentEntity = parts[0] + "." + parts[1]; + String compositionName = parts[2]; + + assertEquals("MyService.MyProjectionEntity", parentEntity); + assertEquals("attachments", compositionName); + } + + @Test + void testInvalidFacetFormat() { + // Test error handling for invalid facet formats + String invalidFacet = "Service.Entity"; // Missing composition + String[] parts = invalidFacet.split("\\."); + + assertTrue(parts.length < 3, "Should detect invalid facet format"); + } +} diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java index 9601713a1..0a3f98001 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMServiceGenericHandlerTest.java @@ -111,6 +111,7 @@ void testCopyAttachments_shouldCopyAttachment() throws IOException { verify(attachmentService, times(1)).copyAttachments(captor.capture(), eq(false)); CopyAttachmentInput input = captor.getValue(); assert input.upId().equals("123"); + assert input.facet().equals("MyService.MyEntity.attachments"); assert input.objectIds().equals(List.of("abc", "xyz")); verify(mockContext, times(1)).setCompleted(); } From c888d77380d649852fdd03a267dbef19aea33641 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 23 Oct 2025 16:07:20 +0530 Subject: [PATCH 7/9] fix for copy link --- .../handler/SDMCustomServiceHandler.java | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index d8b4d67bd..4c925fb7a 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -33,6 +33,26 @@ public class SDMCustomServiceHandler { private final TokenHandler tokenHandler; private final PersistenceService persistenceService; + // Result class for copyAttachmentsToSDM method + private static class CopyAttachmentsResult { + private final List> attachmentsMetadata; + private final List populatedDocuments; + + public CopyAttachmentsResult( + List> attachmentsMetadata, List populatedDocuments) { + this.attachmentsMetadata = attachmentsMetadata; + this.populatedDocuments = populatedDocuments; + } + + public List> getAttachmentsMetadata() { + return attachmentsMetadata; + } + + public List getPopulatedDocuments() { + return populatedDocuments; + } + } + public SDMCustomServiceHandler( SDMService sdmService, List draftService, @@ -70,27 +90,28 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti != null; String folderId = ensureFolderExists(folderName, repositoryId, sdmCredentials, isSystemUser); - CmisDocument cmisDocument = new CmisDocument(); List objectIds = context.getObjectIds(); System.out.println("objectIds: " + objectIds); - List> attachmentsMetadata = + CopyAttachmentsResult copyResult = copyAttachmentsToSDM( context, objectIds, folderId, repositoryId, sdmCredentials, isSystemUser, folderExists); + List> attachmentsMetadata = copyResult.getAttachmentsMetadata(); + List populatedDocuments = copyResult.getPopulatedDocuments(); System.out.println("attachmentsMetadata: " + attachmentsMetadata); String upIdKey = resolveUpIdKey(context, parentEntity, compositionName); System.out.println("upIdKey: " + upIdKey); createDraftEntries( attachmentsMetadata, + populatedDocuments, parentEntity, compositionName, upID, upIdKey, repositoryId, - folderId, - cmisDocument); + folderId); context.setCompleted(); } @@ -113,7 +134,7 @@ private String ensureFolderExists( return folderId; } - private List> copyAttachmentsToSDM( + private CopyAttachmentsResult copyAttachmentsToSDM( AttachmentCopyEventContext context, List objectIds, String folderId, @@ -123,6 +144,7 @@ private List> copyAttachmentsToSDM( boolean folderExists) throws IOException { List> attachmentsMetadata = new ArrayList<>(); + List populatedDocuments = new ArrayList<>(); for (String objectId : objectIds) { CmisDocument cmisDocument = @@ -132,6 +154,12 @@ private List> copyAttachmentsToSDM( cmisDocument.setRepositoryId(repositoryId); cmisDocument.setFolderId(folderId); + // Create individual document for each attachment with its own type and linkUrl + CmisDocument populatedDocument = new CmisDocument(); + populatedDocument.setType(cmisDocument.getType()); + populatedDocument.setUrl(cmisDocument.getUrl()); + populatedDocuments.add(populatedDocument); + try { attachmentsMetadata.add( sdmService.copyAttachment(cmisDocument, sdmCredentials, isSystemUser)); @@ -139,7 +167,8 @@ private List> copyAttachmentsToSDM( handleCopyFailure(context, folderId, folderExists, attachmentsMetadata, e); } } - return attachmentsMetadata; + + return new CopyAttachmentsResult(attachmentsMetadata, populatedDocuments); } private void handleCopyFailure( @@ -206,16 +235,19 @@ private String resolveUpIdKey( private void createDraftEntries( List> attachmentsMetadata, + List populatedDocuments, String parentEntity, String compositionName, String upID, String upIdKey, String repositoryId, - String folderId, - CmisDocument cmisDocument) { - Map updatedFields = new HashMap<>(); + String folderId) { + + for (int i = 0; i < attachmentsMetadata.size(); i++) { + List attachmentMetadata = attachmentsMetadata.get(i); + CmisDocument cmisDocument = populatedDocuments.get(i); + Map updatedFields = new HashMap<>(); - for (List attachmentMetadata : attachmentsMetadata) { String fileName = attachmentMetadata.get(0); System.out.println("fileName: " + fileName); String mimeType = attachmentMetadata.get(1); @@ -231,11 +263,11 @@ private void createDraftEntries( updatedFields.put("folderId", folderId); updatedFields.put("status", "Clean"); updatedFields.put("mimeType", mimeType); - updatedFields.put("type", cmisDocument.getType()); + updatedFields.put("type", cmisDocument.getType()); // Individual type for each attachment updatedFields.put("fileName", fileName); updatedFields.put("HasDraftEntity", false); updatedFields.put("HasActiveEntity", false); - updatedFields.put("linkUrl", cmisDocument.getUrl()); + updatedFields.put("linkUrl", cmisDocument.getUrl()); // Individual linkUrl for each attachment updatedFields.put( "contentId", newObjectId From 9f18241e25ac1bf53c15d197b3b104a09cf3f802 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Thu, 23 Oct 2025 18:46:04 +0530 Subject: [PATCH 8/9] Removed System.out.println --- .../com/sap/cds/sdm/persistence/DBQuery.java | 22 ------------- .../handler/SDMCustomServiceHandler.java | 31 ------------------- .../handler/SDMServiceGenericHandler.java | 9 ------ 3 files changed, 62 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java index 992878f8b..501b330bd 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java +++ b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java @@ -72,41 +72,30 @@ public CmisDocument getAttachmentForObjectID( // Use the new API to resolve the target attachment entity String parentEntity = context.getParentEntity(); - System.out.println("Parent Entity: " + parentEntity); String compositionName = context.getCompositionName(); - System.out.println("Composition Name: " + compositionName); CdsModel model = context.getModel(); - System.out.println("model: " + model); // Find the parent entity Optional optionalParentEntity = model.findEntity(parentEntity); - System.out.println("optionalParentEntity: " + optionalParentEntity); if (optionalParentEntity.isEmpty()) { - System.out.println("optionalParentEntity is empty"); throw new ServiceException("Unable to find parent entity: " + parentEntity); } // Find the composition element in the parent entity Optional compositionElement = optionalParentEntity.get().findElement(compositionName); - System.out.println("compositionElement: " + compositionElement); if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { - System.out.println("compositionElement is empty or not an association"); throw new ServiceException( "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } // Get the target entity of the composition CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); - System.out.println("assocType: " + assocType); String targetEntityName = assocType.getTarget().getQualifiedName(); - System.out.println("targetEntityName: " + targetEntityName); // Find the target attachment entity Optional attachmentEntity = model.findEntity(targetEntityName); - System.out.println("attachmentEntity: " + attachmentEntity); if (attachmentEntity.isEmpty()) { - System.out.println("attachmentEntity is empty"); throw new ServiceException("Unable to find target attachment entity: " + targetEntityName); } @@ -116,41 +105,30 @@ public CmisDocument getAttachmentForObjectID( .columns("linkUrl", "type") .where(doc -> doc.get("objectId").eq(id)); Result result = persistenceService.run(q); - System.out.println("result: " + result); Optional res = result.first(); - System.out.println("res: " + res); CmisDocument cmisDocument = new CmisDocument(); if (res.isPresent()) { Row row = res.get(); - System.out.println("row: " + row); cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); } else { // Check in draft table as well - System.out.println("Inside else"); Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); - System.out.println("attachmentDraftEntity: " + attachmentDraftEntity); if (attachmentDraftEntity.isPresent()) { - System.out.println("attachmentDraftEntity is present"); q = Select.from(attachmentDraftEntity.get()) .columns("linkUrl", "type") .where(doc -> doc.get("objectId").eq(id)); result = persistenceService.run(q); - System.out.println("result: " + result); res = result.first(); - System.out.println("res: " + res); if (res.isPresent()) { - System.out.println("res is present"); Row row = res.get(); - System.out.println("row: " + row); cmisDocument.setType(row.get("type") != null ? row.get("type").toString() : null); cmisDocument.setUrl(row.get("linkUrl") != null ? row.get("linkUrl").toString() : null); } } } - System.out.println("cmisDocument: " + cmisDocument); return cmisDocument; } diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index 4c925fb7a..db689ccc0 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -69,19 +69,12 @@ public SDMCustomServiceHandler( @On(event = RegisterService.EVENT_COPY_ATTACHMENT) public void copyAttachments(AttachmentCopyEventContext context) throws IOException { - System.out.println("Inside copyAttachments handler of SDMCustomServiceHandler"); String parentEntity = context.getParentEntity(); - System.out.println("parentEntity: " + parentEntity); String compositionName = context.getCompositionName(); - System.out.println("compositionName: " + compositionName); String upID = context.getUpId(); - System.out.println("upID: " + upID); String folderName = upID + "__" + compositionName; - System.out.println("folderName: " + folderName); String repositoryId = SDMConstants.REPOSITORY_ID; - System.out.println("repositoryId: " + repositoryId); Boolean isSystemUser = context.getSystemUser(); - System.out.println("isSystemUser: " + isSystemUser); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); // Check if folder exists before trying to create it @@ -91,7 +84,6 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti String folderId = ensureFolderExists(folderName, repositoryId, sdmCredentials, isSystemUser); List objectIds = context.getObjectIds(); - System.out.println("objectIds: " + objectIds); CopyAttachmentsResult copyResult = copyAttachmentsToSDM( @@ -99,10 +91,8 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti List> attachmentsMetadata = copyResult.getAttachmentsMetadata(); List populatedDocuments = copyResult.getPopulatedDocuments(); - System.out.println("attachmentsMetadata: " + attachmentsMetadata); String upIdKey = resolveUpIdKey(context, parentEntity, compositionName); - System.out.println("upIdKey: " + upIdKey); createDraftEntries( attachmentsMetadata, populatedDocuments, @@ -121,7 +111,6 @@ private String ensureFolderExists( throws IOException { String folderId = sdmService.getFolderIdByPath(folderName, repositoryId, sdmCredentials, isSystemUser); - System.out.println("folderId: " + folderId); if (folderId == null) { folderId = sdmService.createFolder( @@ -129,7 +118,6 @@ private String ensureFolderExists( JSONObject jsonObject = new JSONObject(folderId); JSONObject succinctProperties = jsonObject.getJSONObject("succinctProperties"); folderId = succinctProperties.getString("cmis:objectId"); - System.out.println("Created new folder with folderId: " + folderId); } return folderId; } @@ -149,7 +137,6 @@ private CopyAttachmentsResult copyAttachmentsToSDM( for (String objectId : objectIds) { CmisDocument cmisDocument = dbQuery.getAttachmentForObjectID(persistenceService, objectId, context); - System.out.println("cmisDocument: " + cmisDocument); cmisDocument.setObjectId(objectId); cmisDocument.setRepositoryId(repositoryId); cmisDocument.setFolderId(folderId); @@ -179,10 +166,8 @@ private void handleCopyFailure( ServiceException e) throws IOException { if (!folderExists) { - System.out.println("Exception occurred, deleting created folder with folderId: " + folderId); sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); } else { - System.out.println("Exception occurred, deleting copied attachments"); for (List attachmentMetadata : attachmentsMetadata) { sdmService.deleteDocument( "delete", attachmentMetadata.get(2), context.getUserInfo().getName()); @@ -195,38 +180,28 @@ private String resolveUpIdKey( AttachmentCopyEventContext context, String parentEntity, String compositionName) { CdsModel model = context.getModel(); Optional optionalParentEntity = model.findEntity(parentEntity); - System.out.println("optionalParentEntity: " + optionalParentEntity); if (optionalParentEntity.isEmpty()) { throw new ServiceException("Unable to find parent entity: " + parentEntity); } Optional compositionElement = optionalParentEntity.get().findElement(compositionName); - System.out.println("compositionElement: " + compositionElement); if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { throw new ServiceException( "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } CdsAssociationType assocType = (CdsAssociationType) compositionElement.get().getType(); - System.out.println("assocType: " + assocType); String targetEntityName = assocType.getTarget().getQualifiedName(); - System.out.println("targetEntityName: " + targetEntityName); Optional attachmentDraftEntity = model.findEntity(targetEntityName + "_drafts"); - System.out.println("attachmentDraftEntity: " + attachmentDraftEntity); if (attachmentDraftEntity.isPresent()) { Optional upAssociation = attachmentDraftEntity.get().findAssociation("up_"); - System.out.println("upAssociation: " + upAssociation); if (upAssociation.isPresent()) { CdsElement association = upAssociation.get(); - System.out.println("association: " + association); CdsAssociationType upAssocType = association.getType(); - System.out.println("upAssocType: " + upAssocType); List fkElements = upAssocType.refs().map(ref -> "up__" + ref.path()).toList(); - System.out.println("fkElements: " + fkElements); String upIdKey = fkElements.get(0); - System.out.println("upIdKey: " + upIdKey); return upIdKey; } } @@ -249,9 +224,7 @@ private void createDraftEntries( Map updatedFields = new HashMap<>(); String fileName = attachmentMetadata.get(0); - System.out.println("fileName: " + fileName); String mimeType = attachmentMetadata.get(1); - System.out.println("mimeType: " + mimeType); if (mimeType.equalsIgnoreCase("application/internet-shortcut")) { int dotIndex = fileName.lastIndexOf('.'); fileName = fileName.substring(0, dotIndex); @@ -280,14 +253,11 @@ private void createDraftEntries( + ":" + mimeType); updatedFields.put(upIdKey, upID); - System.out.println("updatedFields: " + updatedFields); String baseKeyField = upIdKey != null ? upIdKey.replace("up__", "") : "ID"; var insert = Insert.into(parentEntity, e -> e.filter(e.get(baseKeyField).eq(upID)).to(compositionName)) .entry(updatedFields); - System.out.println("Insert: " + insert); - System.out.println("Using baseKeyField: " + baseKeyField + " for filter"); DraftService matchingService = draftService.stream() @@ -296,7 +266,6 @@ private void createDraftEntries( .orElse(null); if (matchingService != null) { - System.out.println("Using DraftService: " + matchingService.getName()); matchingService.newDraft(insert); } else { throw new ServiceException("No suitable service found for entity: " + parentEntity); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java index fed8878e7..b959d24e3 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMServiceGenericHandler.java @@ -67,14 +67,11 @@ public SDMServiceGenericHandler( @On(event = "copyAttachments") public void copyAttachments(EventContext context) throws IOException { String upID = context.get("up__ID").toString(); - System.out.println("upID: " + upID); String objectIdsString = context.get("objectIds").toString(); - System.out.println("objectIdsString: " + objectIdsString); List objectIds = Arrays.stream(objectIdsString.split(",")).map(String::trim).toList(); // Use the full target qualified name as the facet String facet = context.getTarget().getQualifiedName(); - System.out.println("facet: " + facet); var copyEventInput = new CopyAttachmentInput(upID, facet, objectIds); @@ -100,26 +97,20 @@ public void openAttachment(AttachmentReadContext context) throws Exception { CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel); Optional attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName() + "_drafts"); - System.out.println("attachmentEntity: " + attachmentEntity); Map targetKeys = cqnAnalyzer.analyze((CqnSelect) context.get("cqn")).targetKeyValues(); // get the objectId against the Id String id = targetKeys.get("ID").toString(); - System.out.println("id: " + id); CmisDocument cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); - System.out.println("cmisDocument: " + cmisDocument); if (cmisDocument.getFileName() == null || cmisDocument.getFileName().isEmpty()) { // open attachment is triggered on non-draft entity attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName()); cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); - System.out.println("cmisDocument (non-draft): " + cmisDocument); } if (cmisDocument.getMimeType().equalsIgnoreCase("application/internet-shortcut")) { - System.out.println("Link detected, fetching URL"); - System.out.println("cmisDocument before fetching URL: " + cmisDocument.getUrl()); context.setResult(cmisDocument.getUrl()); } else { context.setResult("None"); From 3ee6619543c4f106a6ce070bc17d782cab2d0cc6 Mon Sep 17 00:00:00 2001 From: "Yashmeet ." Date: Fri, 24 Oct 2025 13:15:00 +0530 Subject: [PATCH 9/9] Review comments --- pom.xml | 2 +- .../sap/cds/sdm/constants/SDMConstants.java | 7 + .../cds/sdm/model/CopyAttachmentsRequest.java | 110 ++++++++++++++++ .../sdm/model/CreateDraftEntriesRequest.java | 121 ++++++++++++++++++ .../com/sap/cds/sdm/persistence/DBQuery.java | 8 +- .../sdm/service/SDMAttachmentsService.java | 3 +- .../handler/SDMCustomServiceHandler.java | 111 +++++++++------- 7 files changed, 308 insertions(+), 54 deletions(-) create mode 100644 sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentsRequest.java create mode 100644 sdm/src/main/java/com/sap/cds/sdm/model/CreateDraftEntriesRequest.java diff --git a/pom.xml b/pom.xml index 2c0a71411..82b3e6e5f 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - 1.0.0-RC1 + 1.5.1-SNAPSHOT 17 ${java.version} ${java.version} diff --git a/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java b/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java index b5915cc07..bf737cdaa 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java +++ b/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java @@ -85,6 +85,13 @@ private SDMConstants() { public static final String FAILED_TO_FETCH_UP_ID = "Failed to fetch up_id"; public static final String FAILED_TO_FETCH_FACET = "Invalid facet format, unable to extract required information."; + public static final String PARENT_ENTITY_NOT_FOUND_ERROR = "Unable to find parent entity: %s"; + public static final String COMPOSITION_NOT_FOUND_ERROR = + "Unable to find composition '%s' in entity: %s"; + public static final String TARGET_ATTACHMENT_ENTITY_NOT_FOUND_ERROR = + "Unable to find target attachment entity: %s"; + public static final String INVALID_FACET_FORMAT_ERROR = + "Invalid facet format. Expected: Service.Entity.Composition, got: %s"; public static String nameConstraintMessage( List fileNameWithRestrictedCharacters, String operation) { diff --git a/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentsRequest.java b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentsRequest.java new file mode 100644 index 000000000..e6e3cc5b0 --- /dev/null +++ b/sdm/src/main/java/com/sap/cds/sdm/model/CopyAttachmentsRequest.java @@ -0,0 +1,110 @@ +package com.sap.cds.sdm.model; + +import com.sap.cds.sdm.service.handler.AttachmentCopyEventContext; +import java.util.List; + +/** + * Parameter object for copyAttachmentsToSDM method to reduce parameter count and improve code + * maintainability. + */ +public class CopyAttachmentsRequest { + private final AttachmentCopyEventContext context; + private final List objectIds; + private final String folderId; + private final String repositoryId; + private final SDMCredentials sdmCredentials; + private final Boolean isSystemUser; + private final boolean folderExists; + + private CopyAttachmentsRequest(Builder builder) { + this.context = builder.context; + this.objectIds = builder.objectIds; + this.folderId = builder.folderId; + this.repositoryId = builder.repositoryId; + this.sdmCredentials = builder.sdmCredentials; + this.isSystemUser = builder.isSystemUser; + this.folderExists = builder.folderExists; + } + + // Getters + public AttachmentCopyEventContext getContext() { + return context; + } + + public List getObjectIds() { + return objectIds; + } + + public String getFolderId() { + return folderId; + } + + public String getRepositoryId() { + return repositoryId; + } + + public SDMCredentials getSdmCredentials() { + return sdmCredentials; + } + + public Boolean getIsSystemUser() { + return isSystemUser; + } + + public boolean isFolderExists() { + return folderExists; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private AttachmentCopyEventContext context; + private List objectIds; + private String folderId; + private String repositoryId; + private SDMCredentials sdmCredentials; + private Boolean isSystemUser; + private boolean folderExists; + + public Builder context(AttachmentCopyEventContext context) { + this.context = context; + return this; + } + + public Builder objectIds(List objectIds) { + this.objectIds = objectIds; + return this; + } + + public Builder folderId(String folderId) { + this.folderId = folderId; + return this; + } + + public Builder repositoryId(String repositoryId) { + this.repositoryId = repositoryId; + return this; + } + + public Builder sdmCredentials(SDMCredentials sdmCredentials) { + this.sdmCredentials = sdmCredentials; + return this; + } + + public Builder isSystemUser(Boolean isSystemUser) { + this.isSystemUser = isSystemUser; + return this; + } + + public Builder folderExists(boolean folderExists) { + this.folderExists = folderExists; + return this; + } + + public CopyAttachmentsRequest build() { + return new CopyAttachmentsRequest(this); + } + } +} diff --git a/sdm/src/main/java/com/sap/cds/sdm/model/CreateDraftEntriesRequest.java b/sdm/src/main/java/com/sap/cds/sdm/model/CreateDraftEntriesRequest.java new file mode 100644 index 000000000..3f8bded5d --- /dev/null +++ b/sdm/src/main/java/com/sap/cds/sdm/model/CreateDraftEntriesRequest.java @@ -0,0 +1,121 @@ +package com.sap.cds.sdm.model; + +import java.util.List; + +/** + * Parameter object for createDraftEntries method to reduce parameter count and improve code + * maintainability. + */ +public class CreateDraftEntriesRequest { + private final List> attachmentsMetadata; + private final List populatedDocuments; + private final String parentEntity; + private final String compositionName; + private final String upID; + private final String upIdKey; + private final String repositoryId; + private final String folderId; + + private CreateDraftEntriesRequest(Builder builder) { + this.attachmentsMetadata = builder.attachmentsMetadata; + this.populatedDocuments = builder.populatedDocuments; + this.parentEntity = builder.parentEntity; + this.compositionName = builder.compositionName; + this.upID = builder.upID; + this.upIdKey = builder.upIdKey; + this.repositoryId = builder.repositoryId; + this.folderId = builder.folderId; + } + + // Getters + public List> getAttachmentsMetadata() { + return attachmentsMetadata; + } + + public List getPopulatedDocuments() { + return populatedDocuments; + } + + public String getParentEntity() { + return parentEntity; + } + + public String getCompositionName() { + return compositionName; + } + + public String getUpID() { + return upID; + } + + public String getUpIdKey() { + return upIdKey; + } + + public String getRepositoryId() { + return repositoryId; + } + + public String getFolderId() { + return folderId; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private List> attachmentsMetadata; + private List populatedDocuments; + private String parentEntity; + private String compositionName; + private String upID; + private String upIdKey; + private String repositoryId; + private String folderId; + + public Builder attachmentsMetadata(List> attachmentsMetadata) { + this.attachmentsMetadata = attachmentsMetadata; + return this; + } + + public Builder populatedDocuments(List populatedDocuments) { + this.populatedDocuments = populatedDocuments; + return this; + } + + public Builder parentEntity(String parentEntity) { + this.parentEntity = parentEntity; + return this; + } + + public Builder compositionName(String compositionName) { + this.compositionName = compositionName; + return this; + } + + public Builder upID(String upID) { + this.upID = upID; + return this; + } + + public Builder upIdKey(String upIdKey) { + this.upIdKey = upIdKey; + return this; + } + + public Builder repositoryId(String repositoryId) { + this.repositoryId = repositoryId; + return this; + } + + public Builder folderId(String folderId) { + this.folderId = folderId; + return this; + } + + public CreateDraftEntriesRequest build() { + return new CreateDraftEntriesRequest(this); + } + } +} diff --git a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java index 501b330bd..1fa13df5d 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java +++ b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java @@ -78,7 +78,8 @@ public CmisDocument getAttachmentForObjectID( // Find the parent entity Optional optionalParentEntity = model.findEntity(parentEntity); if (optionalParentEntity.isEmpty()) { - throw new ServiceException("Unable to find parent entity: " + parentEntity); + throw new ServiceException( + String.format(SDMConstants.PARENT_ENTITY_NOT_FOUND_ERROR, parentEntity)); } // Find the composition element in the parent entity @@ -86,7 +87,7 @@ public CmisDocument getAttachmentForObjectID( optionalParentEntity.get().findElement(compositionName); if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { throw new ServiceException( - "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); + String.format(SDMConstants.COMPOSITION_NOT_FOUND_ERROR, compositionName, parentEntity)); } // Get the target entity of the composition @@ -96,7 +97,8 @@ public CmisDocument getAttachmentForObjectID( // Find the target attachment entity Optional attachmentEntity = model.findEntity(targetEntityName); if (attachmentEntity.isEmpty()) { - throw new ServiceException("Unable to find target attachment entity: " + targetEntityName); + throw new ServiceException( + String.format(SDMConstants.TARGET_ATTACHMENT_ENTITY_NOT_FOUND_ERROR, targetEntityName)); } // Search in active entity first diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java index c73ffbafc..c99fc4dc3 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAttachmentsService.java @@ -10,6 +10,7 @@ import com.sap.cds.feature.attachments.service.model.servicehandler.AttachmentReadEventContext; import com.sap.cds.feature.attachments.service.model.servicehandler.AttachmentRestoreEventContext; import com.sap.cds.feature.attachments.service.model.servicehandler.DeletionUserInfo; +import com.sap.cds.sdm.constants.SDMConstants; import com.sap.cds.sdm.model.CopyAttachmentInput; import com.sap.cds.sdm.service.handler.AttachmentCopyEventContext; import com.sap.cds.services.ServiceDelegator; @@ -40,7 +41,7 @@ public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser) { String[] facetParts = input.facet().split("\\."); if (facetParts.length < 3) { throw new IllegalArgumentException( - "Invalid facet format. Expected: Service.Entity.Composition, got: " + input.facet()); + String.format(SDMConstants.INVALID_FACET_FORMAT_ERROR, input.facet())); } String parentEntity = facetParts[0] + "." + facetParts[1]; // Service.Entity diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java index db689ccc0..63a34e5c0 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMCustomServiceHandler.java @@ -8,6 +8,8 @@ import com.sap.cds.sdm.constants.SDMConstants; import com.sap.cds.sdm.handler.TokenHandler; import com.sap.cds.sdm.model.CmisDocument; +import com.sap.cds.sdm.model.CopyAttachmentsRequest; +import com.sap.cds.sdm.model.CreateDraftEntriesRequest; import com.sap.cds.sdm.model.SDMCredentials; import com.sap.cds.sdm.persistence.DBQuery; import com.sap.cds.sdm.service.RegisterService; @@ -85,23 +87,37 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti List objectIds = context.getObjectIds(); - CopyAttachmentsResult copyResult = - copyAttachmentsToSDM( - context, objectIds, folderId, repositoryId, sdmCredentials, isSystemUser, folderExists); + CopyAttachmentsRequest request = + CopyAttachmentsRequest.builder() + .context(context) + .objectIds(objectIds) + .folderId(folderId) + .repositoryId(repositoryId) + .sdmCredentials(sdmCredentials) + .isSystemUser(isSystemUser) + .folderExists(folderExists) + .build(); + + CopyAttachmentsResult copyResult = copyAttachmentsToSDM(request); List> attachmentsMetadata = copyResult.getAttachmentsMetadata(); List populatedDocuments = copyResult.getPopulatedDocuments(); String upIdKey = resolveUpIdKey(context, parentEntity, compositionName); - createDraftEntries( - attachmentsMetadata, - populatedDocuments, - parentEntity, - compositionName, - upID, - upIdKey, - repositoryId, - folderId); + + CreateDraftEntriesRequest draftRequest = + CreateDraftEntriesRequest.builder() + .attachmentsMetadata(attachmentsMetadata) + .populatedDocuments(populatedDocuments) + .parentEntity(parentEntity) + .compositionName(compositionName) + .upID(upID) + .upIdKey(upIdKey) + .repositoryId(repositoryId) + .folderId(folderId) + .build(); + + createDraftEntries(draftRequest); context.setCompleted(); } @@ -122,24 +138,17 @@ private String ensureFolderExists( return folderId; } - private CopyAttachmentsResult copyAttachmentsToSDM( - AttachmentCopyEventContext context, - List objectIds, - String folderId, - String repositoryId, - SDMCredentials sdmCredentials, - Boolean isSystemUser, - boolean folderExists) + private CopyAttachmentsResult copyAttachmentsToSDM(CopyAttachmentsRequest request) throws IOException { List> attachmentsMetadata = new ArrayList<>(); List populatedDocuments = new ArrayList<>(); - for (String objectId : objectIds) { + for (String objectId : request.getObjectIds()) { CmisDocument cmisDocument = - dbQuery.getAttachmentForObjectID(persistenceService, objectId, context); + dbQuery.getAttachmentForObjectID(persistenceService, objectId, request.getContext()); cmisDocument.setObjectId(objectId); - cmisDocument.setRepositoryId(repositoryId); - cmisDocument.setFolderId(folderId); + cmisDocument.setRepositoryId(request.getRepositoryId()); + cmisDocument.setFolderId(request.getFolderId()); // Create individual document for each attachment with its own type and linkUrl CmisDocument populatedDocument = new CmisDocument(); @@ -149,9 +158,15 @@ private CopyAttachmentsResult copyAttachmentsToSDM( try { attachmentsMetadata.add( - sdmService.copyAttachment(cmisDocument, sdmCredentials, isSystemUser)); + sdmService.copyAttachment( + cmisDocument, request.getSdmCredentials(), request.getIsSystemUser())); } catch (ServiceException e) { - handleCopyFailure(context, folderId, folderExists, attachmentsMetadata, e); + handleCopyFailure( + request.getContext(), + request.getFolderId(), + request.isFolderExists(), + attachmentsMetadata, + e); } } @@ -208,19 +223,11 @@ private String resolveUpIdKey( return null; } - private void createDraftEntries( - List> attachmentsMetadata, - List populatedDocuments, - String parentEntity, - String compositionName, - String upID, - String upIdKey, - String repositoryId, - String folderId) { - - for (int i = 0; i < attachmentsMetadata.size(); i++) { - List attachmentMetadata = attachmentsMetadata.get(i); - CmisDocument cmisDocument = populatedDocuments.get(i); + private void createDraftEntries(CreateDraftEntriesRequest request) { + + for (int i = 0; i < request.getAttachmentsMetadata().size(); i++) { + List attachmentMetadata = request.getAttachmentsMetadata().get(i); + CmisDocument cmisDocument = request.getPopulatedDocuments().get(i); Map updatedFields = new HashMap<>(); String fileName = attachmentMetadata.get(0); @@ -232,8 +239,8 @@ private void createDraftEntries( String newObjectId = attachmentMetadata.get(2); updatedFields.put("objectId", newObjectId); - updatedFields.put("repositoryId", repositoryId); - updatedFields.put("folderId", folderId); + updatedFields.put("repositoryId", request.getRepositoryId()); + updatedFields.put("folderId", request.getFolderId()); updatedFields.put("status", "Clean"); updatedFields.put("mimeType", mimeType); updatedFields.put("type", cmisDocument.getType()); // Individual type for each attachment @@ -245,30 +252,36 @@ private void createDraftEntries( "contentId", newObjectId + ":" - + folderId + + request.getFolderId() + ":" - + parentEntity + + request.getParentEntity() + "." - + compositionName + + request.getCompositionName() + ":" + mimeType); - updatedFields.put(upIdKey, upID); + updatedFields.put(request.getUpIdKey(), request.getUpID()); - String baseKeyField = upIdKey != null ? upIdKey.replace("up__", "") : "ID"; + String baseKeyField = + request.getUpIdKey() != null ? request.getUpIdKey().replace("up__", "") : "ID"; var insert = - Insert.into(parentEntity, e -> e.filter(e.get(baseKeyField).eq(upID)).to(compositionName)) + Insert.into( + request.getParentEntity(), + e -> + e.filter(e.get(baseKeyField).eq(request.getUpID())) + .to(request.getCompositionName())) .entry(updatedFields); DraftService matchingService = draftService.stream() - .filter(ds -> parentEntity.contains(ds.getName())) + .filter(ds -> request.getParentEntity().contains(ds.getName())) .findFirst() .orElse(null); if (matchingService != null) { matchingService.newDraft(insert); } else { - throw new ServiceException("No suitable service found for entity: " + parentEntity); + throw new ServiceException( + "No suitable service found for entity: " + request.getParentEntity()); } } }