From 3f64b3ce9c8d73a9fd16811d1e07f08dfd9d9dfc Mon Sep 17 00:00:00 2001 From: Rashmi Angadi Date: Tue, 7 Apr 2026 10:15:14 +0530 Subject: [PATCH 1/3] SDM binding and technical user customer issues --- sdm/pom.xml | 2 +- .../com/sap/cds/sdm/handler/TokenHandler.java | 2 +- .../sdm/service/SDMAttachmentsService.java | 3 +- .../com/sap/cds/sdm/service/SDMService.java | 3 +- .../sap/cds/sdm/service/SDMServiceImpl.java | 10 ++++-- .../handler/SDMAttachmentsServiceHandler.java | 12 +++++-- .../handler/SDMCustomServiceHandler.java | 11 ++++-- .../sap/cds/sdm/handler/TokenHandlerTest.java | 4 +-- .../cds/sdm/service/SDMServiceImplTest.java | 34 +++++++++++++++---- .../SDMAttachmentsServiceHandlerTest.java | 20 ++++++----- .../handler/SDMCustomServiceHandlerTest.java | 7 ++-- 11 files changed, 77 insertions(+), 31 deletions(-) diff --git a/sdm/pom.xml b/sdm/pom.xml index 8210bbc7d..fad488be0 100644 --- a/sdm/pom.xml +++ b/sdm/pom.xml @@ -34,7 +34,7 @@ src/test/gen 17 17 - 1.3.1 + 1.4.0 1.18.36 0.8.7 3.10.8 diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/TokenHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/TokenHandler.java index f344b6724..ced6701f9 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/TokenHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/TokenHandler.java @@ -71,7 +71,7 @@ public Map getUaaCredentials() { DefaultServiceBindingAccessor.getInstance().getServiceBindings(); ServiceBinding sdmBinding = allServiceBindings.stream() - .filter(binding -> "sdm".equalsIgnoreCase(binding.getServiceName().orElse(null))) + .filter(binding -> binding.getTags().contains("sdm")) .findFirst() .orElseThrow(() -> new IllegalStateException("SDM binding not found")); return sdmBinding.getCredentials(); 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 6fd663b7f..ee834d2ad 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 @@ -181,7 +181,8 @@ public AttachmentModificationResult createAttachment(CreateAttachmentInput input return new AttachmentModificationResult( Boolean.TRUE.equals(createContext.getIsInternalStored()), createContext.getContentId(), - createContext.getData().getStatus()); + createContext.getData().getStatus(), + null); } @Override diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java index 440fdfb7a..e3fd52234 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java @@ -33,7 +33,8 @@ public String getFolderIdByPath( public JSONObject getRepositoryInfo(SDMCredentials sdmCredentials) throws IOException; - public int deleteDocument(String cmisaction, String objectId, String user) throws IOException; + public int deleteDocument(String cmisaction, String objectId, String user, Boolean isSystemUser) + throws IOException; public void readDocument( String objectId, SDMCredentials sdmCredentials, AttachmentReadEventContext context) diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java index 69f1d7e2a..03a80644b 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java @@ -660,13 +660,17 @@ public Map fetchRepositoryData(JSONObject repoInfo, String re } @Override - public int deleteDocument(String cmisaction, String objectId, String user) { + public int deleteDocument(String cmisaction, String objectId, String user, Boolean isSytemUser) { logger.info( - "Deleting document - action: {}, objectId: {}, user: {}", cmisaction, objectId, user); + "Deleting document - action: {}, objectId: {}, user: {},isSystemUser :{}", + cmisaction, + objectId, + user, + isSytemUser); long startTime = System.currentTimeMillis(); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); HttpClient httpClient; - if (user.equals(SDMConstants.SYSTEM_USER)) { + if (isSytemUser) { logger.debug("Using TECHNICAL_USER_FLOW for deletion"); httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, TECHNICAL_USER_FLOW); } else { diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java index 2d391971d..89cf19c7c 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java @@ -107,12 +107,20 @@ public void markAttachmentAsDeleted(AttachmentMarkAsDeletedEventContext context) if (cmisDocuments.isEmpty()) { // deleteFolder API logger.info("Deleting folder: {} for entity: {}", folderId, entity); - sdmService.deleteDocument("deleteTree", folderId, context.getDeletionUserInfo().getName()); + sdmService.deleteDocument( + "deleteTree", + folderId, + context.getDeletionUserInfo().getName(), + context.getDeletionUserInfo().getIsSystemUser()); logger.info("Folder deleted successfully: {}", folderId); } else { if (!isObjectIdPresent(cmisDocuments, objectId)) { logger.info("Deleting document: {} from repository", objectId); - sdmService.deleteDocument("delete", objectId, context.getDeletionUserInfo().getName()); + sdmService.deleteDocument( + "delete", + objectId, + context.getDeletionUserInfo().getName(), + context.getDeletionUserInfo().getIsSystemUser()); logger.info("Document deleted successfully: {}", objectId); } else { logger.debug("ObjectId {} is still referenced, not deleting", objectId); 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 9fe9c8b63..b393a30a9 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 @@ -1525,13 +1525,20 @@ private void handleCopyFailure( logger.error("Copy failure detected, initiating cleanup. Error: {}", e.getMessage()); if (!folderExists) { logger.debug("Deleting newly created folder: {}", folderId); - sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); + sdmService.deleteDocument( + "deleteTree", + folderId, + context.getUserInfo().getName(), + context.getUserInfo().isSystemUser()); } else { logger.debug( "Deleting {} copied attachments from existing folder", attachmentsMetadata.size()); for (Map attachmentMetadata : attachmentsMetadata) { sdmService.deleteDocument( - "delete", attachmentMetadata.get("cmis:objectId"), context.getUserInfo().getName()); + "delete", + attachmentMetadata.get("cmis:objectId"), + context.getUserInfo().getName(), + context.getUserInfo().isSystemUser()); } } throw new ServiceException(e.getMessage()); diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/handler/TokenHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/handler/TokenHandlerTest.java index 8d311fdb3..e999b83d7 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/handler/TokenHandlerTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/handler/TokenHandlerTest.java @@ -140,7 +140,7 @@ public void testGetSDMCredentials() { mockCredentials.put("uaa", mockUaa); mockCredentials.put("uri", "https://mock.service.url"); - Mockito.when(mockServiceBinding.getServiceName()).thenReturn(Optional.of("sdm")); + Mockito.when(mockServiceBinding.getTags()).thenReturn(Collections.singletonList("sdm")); Mockito.when(mockServiceBinding.getCredentials()).thenReturn(mockCredentials); List mockServiceBindings = Collections.singletonList(mockServiceBinding); @@ -202,7 +202,7 @@ public void testGetHttpClientForOnboardFlow() { mockCredentials.put("uaa", mockUaa); mockCredentials.put("uri", "https://mock.service.url"); - Mockito.when(mockServiceBinding.getServiceName()).thenReturn(Optional.of("sdm")); + Mockito.when(mockServiceBinding.getTags()).thenReturn(Collections.singletonList("sdm")); Mockito.when(mockServiceBinding.getCredentials()).thenReturn(mockCredentials); List mockServiceBindings = Collections.singletonList(mockServiceBinding); diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/SDMServiceImplTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/SDMServiceImplTest.java index ef0e70853..ddb27e743 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/service/SDMServiceImplTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/SDMServiceImplTest.java @@ -809,10 +809,14 @@ public void testDeleteFolder() throws IOException { when(response.getEntity()).thenReturn(entity); when(mockContext.getDeletionUserInfo()).thenReturn(deletionUserInfo); when(deletionUserInfo.getName()).thenReturn("system-internal"); + when(deletionUserInfo.getIsSystemUser()).thenReturn(true); SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); int actualResponse = sdmServiceImpl.deleteDocument( - "deleteTree", "objectId", mockContext.getDeletionUserInfo().getName()); + "deleteTree", + "objectId", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser()); assertEquals(200, actualResponse); } finally { mockWebServer.shutdown(); @@ -841,7 +845,10 @@ public void testDeleteFolderAuthorities() throws IOException { SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); int actualResponse = sdmServiceImpl.deleteDocument( - "deleteTree", "objectId", mockContext.getDeletionUserInfo().getName()); + "deleteTree", + "objectId", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser()); assertEquals(200, actualResponse); } finally { mockWebServer.shutdown(); @@ -903,10 +910,14 @@ public void testDeleteDocument() throws IOException { when(tokenHandler.getSDMCredentials()).thenReturn(mockSdmCredentials); when(mockContext.getDeletionUserInfo()).thenReturn(deletionUserInfo); when(deletionUserInfo.getName()).thenReturn("system-internal"); + when(deletionUserInfo.getIsSystemUser()).thenReturn(true); SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); int actualResponse = sdmServiceImpl.deleteDocument( - "delete", "objectId", mockContext.getDeletionUserInfo().getName()); + "delete", + "objectId", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser()); assertEquals(200, actualResponse); } finally { mockWebServer.shutdown(); @@ -934,7 +945,10 @@ public void testDeleteDocumentNamedUserFlow() throws IOException { SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); int actualResponse = sdmServiceImpl.deleteDocument( - "delete", "objectId", mockContext.getDeletionUserInfo().getName()); + "delete", + "objectId", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser()); assertEquals(200, actualResponse); } finally { mockWebServer.shutdown(); @@ -961,10 +975,14 @@ public void testDeleteDocumentObjectNotFound() throws IOException { when(tokenHandler.getSDMCredentials()).thenReturn(mockSdmCredentials); when(mockContext.getDeletionUserInfo()).thenReturn(deletionUserInfo); when(deletionUserInfo.getName()).thenReturn("system-internal"); + when(deletionUserInfo.getIsSystemUser()).thenReturn(true); SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); int actualResponse = sdmServiceImpl.deleteDocument( - "delete", "ewdwe", mockContext.getDeletionUserInfo().getName()); + "delete", + "ewdwe", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser()); assertEquals(404, actualResponse); } finally { mockWebServer.shutdown(); @@ -1296,12 +1314,16 @@ public void testDeleteDocumentThrowsServiceExceptionOnHttpClientError() throws I SDMServiceImpl sdmServiceImpl = new SDMServiceImpl(binding, connectionPool, tokenHandler); when(mockContext.getDeletionUserInfo()).thenReturn(deletionUserInfo); when(deletionUserInfo.getName()).thenReturn("system-internal"); + when(deletionUserInfo.getIsSystemUser()).thenReturn(true); // Ensure ServiceException is thrown assertThrows( ServiceException.class, () -> sdmServiceImpl.deleteDocument( - "delete", "123", mockContext.getDeletionUserInfo().getName())); + "delete", + "123", + mockContext.getDeletionUserInfo().getName(), + mockContext.getDeletionUserInfo().getIsSystemUser())); } @Test diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandlerTest.java index 2701d074e..672ef09ad 100644 --- a/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandlerTest.java +++ b/sdm/src/test/java/unit/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandlerTest.java @@ -1425,7 +1425,8 @@ public void testDocumentDeletion() throws IOException { .deleteDocument( "delete", objectId, - attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getName()); + attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getName(), + attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getIsSystemUser()); } @Test @@ -1461,7 +1462,8 @@ public void testFolderDeletion() throws IOException { .deleteDocument( "deleteTree", folderId, - attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getName()); + attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getName(), + attachmentMarkAsDeletedEventContext.getDeletionUserInfo().getIsSystemUser()); } @Test @@ -2054,7 +2056,7 @@ public void testMarkAttachmentAsDeleted_WithNullObjectId() throws IOException { handlerSpy.markAttachmentAsDeleted(deleteContext); verify(deleteContext).setCompleted(); - verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString()); + verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString(), anyBoolean()); } @Test @@ -2068,7 +2070,7 @@ public void testMarkAttachmentAsDeleted_WithInsufficientContextValues() throws I handlerSpy.markAttachmentAsDeleted(deleteContext); verify(deleteContext).setCompleted(); - verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString()); + verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString(), anyBoolean()); } @Test @@ -2083,7 +2085,7 @@ public void testMarkAttachmentAsDeleted_WithEmptyString() throws IOException { handlerSpy.markAttachmentAsDeleted(deleteContext); verify(deleteContext).setCompleted(); - verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString()); + verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString(), anyBoolean()); } @Test @@ -2103,7 +2105,7 @@ public void testMarkAttachmentAsDeleted_DeleteFolderWhenNoAttachments() throws I handlerSpy.markAttachmentAsDeleted(deleteContext); - verify(sdmService).deleteDocument("deleteTree", "folderId", "testUser"); + verify(sdmService).deleteDocument("deleteTree", "folderId", "testUser", false); verify(deleteContext).setCompleted(); } @@ -2127,7 +2129,7 @@ public void testMarkAttachmentAsDeleted_DeleteObjectWhenNotPresent() throws IOEx handlerSpy.markAttachmentAsDeleted(deleteContext); - verify(sdmService).deleteDocument("delete", "objectId", "testUser"); + verify(sdmService).deleteDocument("delete", "objectId", "testUser", false); verify(deleteContext).setCompleted(); } @@ -2151,7 +2153,7 @@ public void testMarkAttachmentAsDeleted_ObjectIdPresent() throws IOException { handlerSpy.markAttachmentAsDeleted(deleteContext); - verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString()); + verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString(), anyBoolean()); verify(deleteContext).setCompleted(); } @@ -2416,7 +2418,7 @@ public void testMarkAttachmentAsDeleted_MultipleObjectsInFolder() throws IOExcep handlerSpy.markAttachmentAsDeleted(deleteContext); // Should not call delete on either document since target is present - verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString()); + verify(sdmService, never()).deleteDocument(anyString(), anyString(), anyString(), anyBoolean()); verify(deleteContext).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 c128b437e..437410755 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 @@ -242,7 +242,8 @@ void testCopyAttachments_AttachmentCopyFails() throws IOException { }); // Verify that deleteDocument was called for cleanup of the first successful attachment - verify(sdmService, times(1)).deleteDocument(eq("delete"), eq(OBJECT_ID), eq("testUser")); + verify(sdmService, times(1)) + .deleteDocument(eq("delete"), eq(OBJECT_ID), eq("testUser"), eq(false)); assertTrue(exception.getMessage().contains("Copy failed")); } @@ -279,7 +280,7 @@ void testCopyAttachments_AttachmentCopyFails_FolderDoesNotExist() throws IOExcep }); // Should attempt to delete the folder - verify(sdmService, times(1)).deleteDocument(eq("deleteTree"), eq(FOLDER_ID), any()); + verify(sdmService, times(1)).deleteDocument(eq("deleteTree"), eq(FOLDER_ID), any(), any()); assertTrue(ex.getMessage().contains("Copy failed")); } @@ -320,7 +321,7 @@ void testCopyAttachments_AttachmentCopyFails_FolderExists_AttachmentsDeleted() }); // Should attempt to delete the copied attachment - verify(sdmService, times(1)).deleteDocument(eq("delete"), eq(OBJECT_ID), any()); + verify(sdmService, times(1)).deleteDocument(eq("delete"), eq(OBJECT_ID), any(), any()); assertTrue(ex.getMessage().contains("Copy failed")); } From 23fda2123d58fdfcc059fef5e69d6927306841bb Mon Sep 17 00:00:00 2001 From: Rashmi Angadi Date: Wed, 8 Apr 2026 14:24:05 +0530 Subject: [PATCH 2/3] Changes for scannedAt --- .../java/com/sap/cds/sdm/service/SDMAttachmentsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ee834d2ad..ebebb9c5b 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 @@ -182,7 +182,7 @@ public AttachmentModificationResult createAttachment(CreateAttachmentInput input Boolean.TRUE.equals(createContext.getIsInternalStored()), createContext.getContentId(), createContext.getData().getStatus(), - null); + Instant.now()); } @Override From 3217451e39e773452b1c1a4cbdd3f4559694a981 Mon Sep 17 00:00:00 2001 From: Rashmi Angadi Date: Wed, 8 Apr 2026 15:36:52 +0530 Subject: [PATCH 3/3] Update SDMAttachmentsServiceHandler.java --- .../cds/sdm/service/handler/SDMAttachmentsServiceHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java index 89cf19c7c..d041c8fe5 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/handler/SDMAttachmentsServiceHandler.java @@ -25,6 +25,7 @@ import com.sap.cds.services.utils.StringUtils; import java.io.IOException; import java.io.InputStream; +import java.time.Instant; import java.util.*; import java.util.stream.Collectors; import org.json.JSONObject; @@ -524,6 +525,7 @@ private void handleCreateDocumentResult( eventContext.setContentId( existing.getObjectId() + ":" + existing.getFolderId() + ":" + activeEntityName); eventContext.getData().setStatus("Clean"); + eventContext.getData().setScannedAt(Instant.now()); eventContext.getData().setContent(null); eventContext.setCompleted(); return; @@ -628,6 +630,7 @@ private void finalizeContext( + ":" + eventContext.getAttachmentEntity().getQualifiedName()); eventContext.getData().setStatus("Clean"); + eventContext.getData().setScannedAt(Instant.now()); eventContext.getData().setContent(null); eventContext.setCompleted(); logger.debug("Attachment context finalized and marked as completed");