From 548bae31abccb30f47949cba9cda2deea791bff9 Mon Sep 17 00:00:00 2001 From: deepikaSingh2711 Date: Mon, 23 Feb 2026 15:20:04 +0530 Subject: [PATCH 1/2] Added logs --- .../SDMCreateAttachmentsHandler.java | 61 +++++++-- .../SDMReadAttachmentsHandler.java | 51 +++++-- .../SDMUpdateAttachmentsHandler.java | 54 ++++++-- .../helper/AttachmentsHandlerUtils.java | 50 ++++++- .../helper/SDMBeforeReadItemsModifier.java | 6 + .../common/SDMApplicationHandlerHelper.java | 7 +- .../common/SDMAssociationCascader.java | 14 ++ .../handler/common/SDMAttachmentsReader.java | 29 +++- .../cds/sdm/handler/common/SDMNodeTree.java | 8 ++ .../sdm/service/DocumentUploadService.java | 61 ++++++++- .../cds/sdm/service/ReadAheadInputStream.java | 8 ++ .../com/sap/cds/sdm/service/RetryUtils.java | 3 + .../cds/sdm/service/SDMAdminServiceImpl.java | 7 + .../sdm/service/SDMAttachmentsService.java | 13 ++ .../cds/sdm/service/SDMPropertySupplier.java | 11 +- .../sap/cds/sdm/service/SDMServiceImpl.java | 66 ++++++++- .../handler/SDMAttachmentsServiceHandler.java | 125 +++++++++++++++--- .../handler/SDMCustomServiceHandler.java | 51 +++++++ .../handler/SDMServiceGenericHandler.java | 95 +++++++++++-- .../com/sap/cds/sdm/utilities/SDMUtils.java | 16 ++- 20 files changed, 663 insertions(+), 73 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java index 84a5c73a1..8d19c8ded 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java @@ -59,8 +59,10 @@ public SDMCreateAttachmentsHandler( @Before @HandlerOrder(HandlerOrder.DEFAULT) public void processBefore(CdsCreateEventContext context, List data) throws IOException { - logger.info("Target Entity : " + context.getTarget().getQualifiedName()); - logger.debug("CDS Data attachments : " + data); + logger.info( + "START: Process attachments before persistence for entity: {}", + context.getTarget().getQualifiedName()); + logger.debug("Number of entities to process: {}", data.size()); for (CdsData entityData : data) { Map> attachmentCompositionDetails = @@ -70,11 +72,12 @@ public void processBefore(CdsCreateEventContext context, List data) thr persistenceService, context.getTarget().getQualifiedName(), entityData); - logger.info("Attachment compositions present in CDS Model : " + attachmentCompositionDetails); + logger.debug("Attachment compositions present: {}", attachmentCompositionDetails.keySet()); updateName(context, data, attachmentCompositionDetails); // Remove uploadStatus from attachment data to prevent validation errors cleanupReadonlyContextsForAttachments(context, entityData, attachmentCompositionDetails); } + logger.info("END: Process attachments before persistence"); } @After @@ -82,9 +85,10 @@ public void processBefore(CdsCreateEventContext context, List data) thr public void processAfter(CdsCreateEventContext context, List data) { // Update uploadStatus to Success after entity is persisted logger.info( - "Post-processing attachments after persistence for entity: {}", + "START: Post-processing attachments after persistence for entity: {}", context.getTarget().getQualifiedName()); + int totalProcessed = 0; for (CdsData entityData : data) { Map> attachmentCompositionDetails = AttachmentsHandlerUtils.getAttachmentCompositionDetails( @@ -107,6 +111,10 @@ public void processAfter(CdsCreateEventContext context, List data) { targetEntity, entityData, attachmentCompositionName); if (attachments != null) { + logger.debug( + "Processing {} attachments for composition: {}", + attachments.size(), + attachmentCompositionName); for (Map attachment : attachments) { String id = (String) attachment.get("ID"); String uploadStatus = (String) attachment.get("uploadStatus"); @@ -114,16 +122,18 @@ public void processAfter(CdsCreateEventContext context, List data) { CmisDocument cmisDocument = new CmisDocument(); cmisDocument.setAttachmentId(id); cmisDocument.setUploadStatus(uploadStatus); + logger.debug("Saving uploadStatus: {} for attachment ID: {}", uploadStatus, id); // Update uploadStatus to Success in database if it was InProgress dbQuery.saveUploadStatusToAttachment( attachmentEntity.get(), persistenceService, cmisDocument); - logger.debug("Updated uploadStatus to Success for attachment ID: {}", id); + totalProcessed++; } } } } } } + logger.info("END: Post-processing completed. Processed {} attachments", totalProcessed); } @Before @@ -277,10 +287,16 @@ private void processAttachment( List scanFailedFiles, List uploadInProgressFiles) throws IOException { + long startTime = System.currentTimeMillis(); String id = (String) attachment.get("ID"); String filenameInRequest = (String) attachment.get("fileName"); String descriptionInRequest = (String) attachment.get("note"); String objectId = (String) attachment.get("objectId"); + logger.debug( + "START: Process attachment - ID: {}, fileName: {}, objectId: {}", + id, + filenameInRequest, + objectId); // Fetch original data from DB CmisDocument cmisDocument = @@ -290,6 +306,7 @@ private void processAttachment( // Check upload status and collect problematic files if (checkUploadStatus( attachment, fileNameInDB, filenameInRequest, scanFailedFiles, uploadInProgressFiles)) { + logger.debug("Upload status check failed, skipping further processing for ID: {}", id); return; // Skip further processing if upload status is problematic } @@ -316,6 +333,10 @@ private void processAttachment( filesNotFound, filesWithUnsupportedProperties, badRequest); + logger.debug( + "END: Process attachment - ID: {} completed in {} ms", + id, + (System.currentTimeMillis() - startTime)); } private boolean checkUploadStatus( @@ -333,10 +354,12 @@ private boolean checkUploadStatus( String fileName = fileNameInDB != null ? fileNameInDB : filenameInRequest; if (uploadStatus.equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) { + logger.warn("Upload in progress for file: {}", fileName); uploadInProgressFiles.add(fileName); return true; } if (uploadStatus.equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_SCAN_FAILED)) { + logger.warn("Scan failed for file: {}", fileName); scanFailedFiles.add(fileName); return true; } @@ -348,6 +371,7 @@ private boolean checkUploadStatus( private SDMAttachmentData fetchSDMData( CdsCreateEventContext context, String objectId, SDMCredentials sdmCredentials) throws IOException { + logger.debug("Fetching attachment data from SDM for objectId: {}", objectId); JSONObject sdmAttachmentData = AttachmentsHandlerUtils.fetchAttachmentDataFromSDM( sdmService, objectId, sdmCredentials, context.getUserInfo().isSystemUser()); @@ -362,6 +386,10 @@ private SDMAttachmentData fetchSDMData( if (succinctProperties.has("cmis:description")) { descriptionInSDM = succinctProperties.getString("cmis:description"); } + logger.debug( + "Retrieved from SDM - fileName: {}, hasDescription: {}", + fileNameInSDM, + descriptionInSDM != null); return new SDMAttachmentData(fileNameInSDM, descriptionInSDM); } @@ -414,8 +442,9 @@ private void updateAndSendToSDM( false); logger.debug( - "Creating attachment in SDM - ID: {}, properties count: {}", + "Creating attachment in SDM - ID: {}, fileName: {}, properties count: {}", id, + filenameInRequest, updatedSecondaryProperties.size()); try { @@ -427,7 +456,7 @@ private void updateAndSendToSDM( secondaryPropertiesWithInvalidDefinitions, context.getUserInfo().isSystemUser()); - logger.debug("SDM create response code: {} for attachment ID: {}", responseCode, id); + logger.info("SDM update response code: {} for attachment ID: {}", responseCode, id); AttachmentsHandlerUtils.handleSDMUpdateResponse( responseCode, attachment, @@ -440,6 +469,7 @@ private void updateAndSendToSDM( duplicateFileNameList, filesNotFound); } catch (ServiceException e) { + logger.error("Error updating attachment {} in SDM: {}", id, e.getMessage(), e); AttachmentsHandlerUtils.handleSDMServiceException( e, attachment, @@ -464,6 +494,8 @@ private void handleWarnings( List noSDMRoles, String contextInfo) { if (!fileNameWithRestrictedCharacters.isEmpty()) { + logger.warn( + "Files with restricted characters in filename: {}", fileNameWithRestrictedCharacters); context .getMessages() .warn( @@ -471,6 +503,7 @@ private void handleWarnings( + contextInfo); } if (!duplicateFileNameList.isEmpty()) { + logger.warn("Duplicate filenames detected: {}", duplicateFileNameList); context .getMessages() .warn( @@ -478,6 +511,7 @@ private void handleWarnings( + contextInfo); } if (!filesNotFound.isEmpty()) { + logger.warn("Files not found in SDM: {}", filesNotFound); context.getMessages().warn(SDMErrorMessages.fileNotFound(filesNotFound) + contextInfo); } if (!filesWithUnsupportedProperties.isEmpty()) { @@ -494,6 +528,7 @@ private void handleWarnings( invalidPropertyNames.add(propertyTitles.get(file)); } if (!invalidPropertyNames.isEmpty()) { + logger.warn("Files with unsupported properties: {}", invalidPropertyNames); context .getMessages() .warn( @@ -502,9 +537,11 @@ private void handleWarnings( } if (!badRequest.isEmpty()) { + logger.warn("Bad request errors: {}", badRequest.keySet()); context.getMessages().warn(SDMErrorMessages.badRequestMessage(badRequest) + contextInfo); } if (!noSDMRoles.isEmpty()) { + logger.warn("No SDM roles for files: {}", noSDMRoles); context .getMessages() .warn( @@ -545,7 +582,7 @@ private void cleanupReadonlyContextsForAttachments( for (Map.Entry> entry : attachmentCompositionDetails.entrySet()) { String attachmentCompositionName = entry.getValue().get("name"); - logger.info( + logger.debug( "Cleaning up SDM_READONLY_CONTEXT for composition: {}", attachmentCompositionName); // Fetch attachments for this specific composition @@ -554,7 +591,7 @@ private void cleanupReadonlyContextsForAttachments( targetEntity, entityData, attachmentCompositionName); if (attachments != null && !attachments.isEmpty()) { - logger.info( + logger.debug( "Found {} attachments in composition: {}", attachments.size(), attachmentCompositionName); @@ -562,15 +599,15 @@ private void cleanupReadonlyContextsForAttachments( for (int i = 0; i < attachments.size(); i++) { Map attachment = attachments.get(i); if (attachment.containsKey(SDM_READONLY_CONTEXT)) { - logger.info( - " Removing SDM_READONLY_CONTEXT from attachment [{}] in {}", + logger.debug( + "Removing SDM_READONLY_CONTEXT from attachment [{}] in {}", i, attachmentCompositionName); attachment.remove(SDM_READONLY_CONTEXT); } } } else { - logger.info("No attachments found for composition: {}", attachmentCompositionName); + logger.debug("No attachments found for composition: {}", attachmentCompositionName); } } } diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMReadAttachmentsHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMReadAttachmentsHandler.java index aa14eb739..cc71211e0 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMReadAttachmentsHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMReadAttachmentsHandler.java @@ -69,9 +69,11 @@ public SDMReadAttachmentsHandler( before read event when the context is guaranteed to be present. */ private void setErrorMessagesInCache(CdsReadEventContext context) { + logger.debug("Setting error messages in cache"); // Check if cache is available Cache errorMessageCache = CacheConfig.getErrorMessageCache(); if (errorMessageCache == null) { + logger.debug("Error message cache not initialized, skipping"); return; // Cache not initialized, skip } @@ -81,11 +83,13 @@ private void setErrorMessagesInCache(CdsReadEventContext context) { String cacheValue = errorMessageCache.get(cacheCheckKey); if ("true".equals(cacheValue)) { + logger.debug("Error messages already cached, skipping"); return; // Skip processing if already cached } Map errorMessages = SDMErrorMessages.getAllErrorMessages(); Map errorKeys = SDMErrorKeys.getAllErrorKeys(); + logger.debug("Caching {} error messages", errorMessages.size()); String localizedMessage; String localizedErrorMessageKey; for (Map.Entry entry : errorMessages.entrySet()) { @@ -108,13 +112,18 @@ private void setErrorMessagesInCache(CdsReadEventContext context) { // Mark that localized error messages have been cached errorMessageCache.put(cacheCheckKey, "true"); + logger.debug("Error messages cached successfully"); } @Before @HandlerOrder(HandlerOrder.EARLY + 500) public void processBefore(CdsReadEventContext context) throws IOException { + logger.info("Processing read request for entity: {}", context.getTarget().getQualifiedName()); + logger.debug( + "START: Reading attachments for entity: {}", context.getTarget().getQualifiedName()); String repositoryId = SDMConstants.REPOSITORY_ID; if (repositoryId == null) { + logger.debug("Repository ID is null, skipping processing"); return; } setErrorMessagesInCache(context); @@ -122,10 +131,14 @@ public void processBefore(CdsReadEventContext context) throws IOException { try { // update the uploadStatus of all blank attachments with success this is for existing // attachments + logger.debug("Target is a media entity, processing attachment logic"); RepoValue repoValue = checkRepositoryTypeWithFallback(repositoryId, context); // Only process virus scan logic if repository info is available if (repoValue != null) { + logger.debug( + "Repository value found. Async virus scan enabled: {}", + repoValue.getIsAsyncVirusScanEnabled()); Optional attachmentDraftEntity = context.getModel().findEntity(context.getTarget().getQualifiedName() + "_drafts"); String upIdKey = "", upID = ""; @@ -133,13 +146,15 @@ public void processBefore(CdsReadEventContext context) throws IOException { upIdKey = SDMUtils.getUpIdKey(attachmentDraftEntity.get()); CqnSelect select = (CqnSelect) context.get("cqn"); upID = SDMUtils.fetchUPIDFromCQN(select, attachmentDraftEntity.get()); + logger.debug("Processing attachments for upID: {}", upID); if (!repoValue.getIsAsyncVirusScanEnabled()) { - + logger.debug("Sync virus scan mode: updating in-progress upload status to success"); dbQuery.updateInProgressUploadStatusToSuccess( attachmentDraftEntity.get(), persistenceService, upID, upIdKey); } if (repoValue.getIsAsyncVirusScanEnabled()) { + logger.debug("Async virus scan mode: processing virus scan in-progress attachments"); processVirusScanInProgressAttachments(context, upID, upIdKey); } } @@ -148,12 +163,15 @@ public void processBefore(CdsReadEventContext context) throws IOException { CdsModel cdsModel = context.getModel(); List fieldNames = getAttachmentAssociations(cdsModel, context.getTarget(), "", new ArrayList<>()); + logger.debug("Found {} attachment associations", fieldNames.size()); // Create a combined modifier that handles both expand scenarios and repositoryId filter final SDMBeforeReadItemsModifier itemsModifier = new SDMBeforeReadItemsModifier(fieldNames); final Predicate repositoryFilter = CQL.or(CQL.get("repositoryId").eq(repositoryId), CQL.get("repositoryId").isNull()); + logger.debug( + "Creating CQN modifier with {} field names and repository filter", fieldNames.size()); CqnSelect modifiedCqn = CQL.copy( @@ -176,7 +194,11 @@ public Predicate where(Predicate where) { } }); context.setCqn(modifiedCqn); + logger.debug("CQN query modified with repository filter and required fields"); } else { + logger.warn( + "Repository value is null for repository ID: {}. Proceeding with limited functionality", + repositoryId); context.setCqn(context.getCqn()); } } catch (Exception e) { @@ -186,8 +208,12 @@ public Predicate where(Predicate where) { } } else { + logger.debug( + "Target entity {} is not a media entity, skipping attachment processing", + context.getTarget().getQualifiedName()); context.setCqn(context.getCqn()); } + logger.debug("END: Read attachments processing completed"); } /** @@ -198,6 +224,7 @@ private List getAttachmentAssociations( CdsModel model, CdsEntity entity, String associationName, List processedEntities) { List associationNames = new ArrayList<>(); if (SDMApplicationHandlerHelper.isMediaEntity(entity)) { + logger.debug("Found media entity association: {}", associationName); associationNames.add(associationName); } @@ -237,6 +264,7 @@ private List getAttachmentAssociations( private void processVirusScanInProgressAttachments( CdsReadEventContext context, String upID, String upIDkey) { try { + logger.debug("START: Processing virus scan in-progress attachments for upID: {}", upID); // Get the statuses of existing attachments and assign color code // Get all attachments with virus scan in progress Optional attachmentDraftEntity = @@ -251,6 +279,8 @@ private void processVirusScanInProgressAttachments( persistenceService, upID, upIDkey); + logger.debug( + "Found {} attachments with virus scan in progress", attachmentsInProgress.size()); // Get SDM credentials var sdmCredentials = tokenHandler.getSDMCredentials(); @@ -267,11 +297,13 @@ private void processVirusScanInProgressAttachments( if (!attachmentsInProgress.isEmpty()) { logger.info( - "Processed {} attachments with virus scan in progress", attachmentsInProgress.size()); + "Processed {} attachments with virus scan status updates", + attachmentsInProgress.size()); } + logger.debug("END: Process virus scan in-progress attachments"); } catch (Exception e) { - logger.error("Error processing virus scan in progress attachments: {}", e.getMessage()); + logger.error("Error processing virus scan in progress attachments: {}", e.getMessage(), e); } } @@ -293,8 +325,8 @@ private void processAttachmentVirusScanStatus( try { String objectId = attachment.getObjectId(); if (objectId != null && !objectId.isEmpty()) { - logger.info( - "Processing attachment with objectId: {} and filename: {}", + logger.debug( + "Checking virus scan status for objectId: {}, filename: {}", objectId, attachment.getFileName()); @@ -309,10 +341,13 @@ private void processAttachmentVirusScanStatus( String scanStatus = null; if (succinctProperties.has("sap:virusScanStatus")) { scanStatus = succinctProperties.getString("sap:virusScanStatus"); + logger.debug("Virus scan status from SDM: {}", scanStatus); + } else { + logger.debug("No virus scan status found in SDM response for objectId: {}", objectId); } - logger.info( - "Successfully retrieved object for attachmentId: {}, filename: {}, scanStatus: {}", + logger.debug( + "Retrieved object for attachmentId: {}, filename: {}, scanStatus: {}", attachment.getAttachmentId(), currentFileName, scanStatus); @@ -326,7 +361,7 @@ private void processAttachmentVirusScanStatus( persistenceService, objectId, scanStatusEnum); - logger.info( + logger.debug( "Updated uploadStatus for objectId: {} based on scanStatus: {}", objectId, scanStatus); diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java index 05c90c2c4..2f07d0643 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java @@ -38,7 +38,7 @@ public class SDMUpdateAttachmentsHandler implements EventHandler { private final SDMService sdmService; private final TokenHandler tokenHandler; private final DBQuery dbQuery; - private static final Logger logger = LoggerFactory.getLogger(CacheConfig.class); + private static final Logger logger = LoggerFactory.getLogger(SDMUpdateAttachmentsHandler.class); public SDMUpdateAttachmentsHandler( PersistenceService persistenceService, @@ -54,6 +54,9 @@ public SDMUpdateAttachmentsHandler( @Before @HandlerOrder(OrderConstants.Before.CHECK_CAPABILITIES - 500) public void preserveUploadStatus(CdsUpdateEventContext context, List data) { + logger.debug( + "Preserving uploadStatus field before CDS processing for entity: {}", + context.getTarget().getQualifiedName()); // Preserve uploadStatus before CDS removes readonly fields SDMUtils.preserveReadonlyFields(context.getTarget(), data); } @@ -63,9 +66,10 @@ public void preserveUploadStatus(CdsUpdateEventContext context, List da public void processAfter(CdsUpdateEventContext context, List data) { // Update uploadStatus to Success after entity is persisted logger.info( - "Post-processing attachments after persistence for entity: {}", + "START: Post-processing attachments after persistence for entity: {}", context.getTarget().getQualifiedName()); + int totalProcessed = 0; for (CdsData entityData : data) { Map> attachmentCompositionDetails = AttachmentsHandlerUtils.getAttachmentCompositionDetails( @@ -88,6 +92,10 @@ public void processAfter(CdsUpdateEventContext context, List data) { targetEntity, entityData, attachmentCompositionName); if (attachments != null) { + logger.debug( + "Processing {} attachments for composition: {}", + attachments.size(), + attachmentCompositionName); for (Map attachment : attachments) { String id = (String) attachment.get("ID"); String uploadStatus = (String) attachment.get("uploadStatus"); @@ -96,20 +104,27 @@ public void processAfter(CdsUpdateEventContext context, List data) { cmisDocument.setAttachmentId(id); cmisDocument.setUploadStatus(uploadStatus); // Update uploadStatus to Success in database if it was InProgress + logger.debug("Saving uploadStatus: {} for attachment ID: {}", uploadStatus, id); dbQuery.saveUploadStatusToAttachment( attachmentEntity.get(), persistenceService, cmisDocument); - logger.debug("Updated uploadStatus to Success for attachment ID: {}", id); + totalProcessed++; } } } } } } + logger.info("END: Post-processing completed. Updated {} attachments", totalProcessed); } @Before @HandlerOrder(HandlerOrder.DEFAULT) public void processBefore(CdsUpdateEventContext context, List data) throws IOException { + logger.info( + "START: Process attachments before persistence for entity: {}", + context.getTarget().getQualifiedName()); + logger.debug("Number of entities to update: {}", data.size()); + // Get comprehensive attachment composition details for each entity for (CdsData entityData : data) { Map> attachmentCompositionDetails = @@ -119,13 +134,14 @@ public void processBefore(CdsUpdateEventContext context, List data) thr persistenceService, context.getTarget().getQualifiedName(), entityData); - logger.info("Attachment compositions present in CDS Model : " + attachmentCompositionDetails); + logger.debug("Attachment compositions present: {}", attachmentCompositionDetails.keySet()); updateName(context, data, attachmentCompositionDetails); // Remove uploadStatus from attachment data to prevent validation errors cleanupReadonlyContextsForAttachments(context, entityData, attachmentCompositionDetails); } + logger.info("END: Process attachments before persistence"); } public void updateName( @@ -175,6 +191,7 @@ private void renameDocument( String attachmentCompositionName, String contextInfo) throws IOException { + logger.debug("Renaming documents for composition: {}", attachmentCompositionName); List duplicateFileNameList = new ArrayList<>(); Map secondaryPropertiesWithInvalidDefinitions; List fileNameWithRestrictedCharacters = new ArrayList<>(); @@ -239,6 +256,7 @@ private void processAttachments( Map secondaryPropertiesWithInvalidDefinitions, List noSDMRoles) throws IOException { + logger.debug("Processing {} attachments for update", attachments.size()); List scanFailedFiles = new ArrayList<>(); List uploadInProgressFiles = new ArrayList<>(); @@ -262,6 +280,10 @@ private void processAttachments( // Throw exception if any files failed scan or upload in progress if (!scanFailedFiles.isEmpty() || !uploadInProgressFiles.isEmpty()) { + logger.warn( + "Blocking update due to scan failures: {}, uploads in progress: {}", + scanFailedFiles.size(), + uploadInProgressFiles.size()); StringBuilder errorMessage = new StringBuilder(); if (!scanFailedFiles.isEmpty()) { if (errorMessage.length() > 0) { @@ -383,10 +405,12 @@ private boolean handleUploadStatusCheck( String fileName = fileNameInDB != null ? fileNameInDB : filenameInRequest; if (uploadStatus.equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_SCAN_FAILED)) { + logger.warn("Scan failed for file: {}", fileName); scanFailedFiles.add(fileName); return true; } if (uploadStatus.equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) { + logger.warn("Upload in progress for file: {}", fileName); uploadInProgressFiles.add(fileName); return true; } @@ -402,6 +426,7 @@ private AttachmentDetails fetchAttachmentDetails( SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { + logger.debug("Fetching attachment details from SDM for objectId: {}", objectId); String finalFileNameInDB = fileNameInDB; String descriptionInDB = null; @@ -417,6 +442,10 @@ private AttachmentDetails fetchAttachmentDetails( if (succinctProperties.has("cmis:description")) { descriptionInDB = succinctProperties.getString("cmis:description"); } + logger.debug( + "Retrieved from SDM - fileName: {}, hasDescription: {}", + finalFileNameInDB, + descriptionInDB != null); } return new AttachmentDetails(finalFileNameInDB, descriptionInDB); @@ -536,6 +565,8 @@ private void handleWarnings( List noSDMRoles, String contextInfo) { if (!fileNameWithRestrictedCharacters.isEmpty()) { + logger.warn( + "Files with restricted characters in filename: {}", fileNameWithRestrictedCharacters); context .getMessages() .warn( @@ -543,6 +574,7 @@ private void handleWarnings( + contextInfo); } if (!duplicateFileNameList.isEmpty()) { + logger.warn("Duplicate filenames detected: {}", duplicateFileNameList); context .getMessages() .warn( @@ -550,6 +582,7 @@ private void handleWarnings( SDMErrorMessages.duplicateFilenameFormat(duplicateFileNameList), contextInfo)); } if (!filesNotFound.isEmpty()) { + logger.warn("Files not found in SDM: {}", filesNotFound); context.getMessages().warn(SDMErrorMessages.fileNotFound(filesNotFound) + contextInfo); } if (!filesWithUnsupportedProperties.isEmpty()) { @@ -566,6 +599,7 @@ private void handleWarnings( invalidPropertyNames.add(propertyTitles.get(file)); } if (!invalidPropertyNames.isEmpty()) { + logger.warn("Files with unsupported properties: {}", invalidPropertyNames); context .getMessages() .warn( @@ -573,9 +607,11 @@ private void handleWarnings( } } if (!badRequest.isEmpty()) { + logger.warn("Bad request errors: {}", badRequest.keySet()); context.getMessages().warn(SDMErrorMessages.badRequestMessage(badRequest) + contextInfo); } if (!noSDMRoles.isEmpty()) { + logger.warn("No SDM roles for files: {}", noSDMRoles); context .getMessages() .warn( @@ -594,7 +630,7 @@ private void cleanupReadonlyContextsForAttachments( for (Map.Entry> entry : attachmentCompositionDetails.entrySet()) { String attachmentCompositionName = entry.getValue().get("name"); - logger.info( + logger.debug( "Cleaning up SDM_READONLY_CONTEXT for composition: {}", attachmentCompositionName); // Fetch attachments for this specific composition @@ -603,7 +639,7 @@ private void cleanupReadonlyContextsForAttachments( targetEntity, entityData, attachmentCompositionName); if (attachments != null && !attachments.isEmpty()) { - logger.info( + logger.debug( "Found {} attachments in composition: {}", attachments.size(), attachmentCompositionName); @@ -611,15 +647,15 @@ private void cleanupReadonlyContextsForAttachments( for (int i = 0; i < attachments.size(); i++) { Map attachment = attachments.get(i); if (attachment.containsKey(SDM_READONLY_CONTEXT)) { - logger.info( - " Removing SDM_READONLY_CONTEXT from attachment [{}] in {}", + logger.debug( + "Removing SDM_READONLY_CONTEXT from attachment [{}] in {}", i, attachmentCompositionName); attachment.remove(SDM_READONLY_CONTEXT); } } } else { - logger.info("No attachments found for composition: {}", attachmentCompositionName); + logger.debug("No attachments found for composition: {}", attachmentCompositionName); } } } diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java index d9997cba9..b9955d81f 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java @@ -44,11 +44,19 @@ private AttachmentsHandlerUtils() { */ public static List getAttachmentEntityPaths( CdsModel model, CdsEntity entity, PersistenceService persistenceService) { + logger.debug("Getting attachment entity paths for: {}", entity.getQualifiedName()); try { SDMAssociationCascader cascader = new SDMAssociationCascader(); SDMAttachmentsReader reader = new SDMAttachmentsReader(cascader, persistenceService); - return reader.getAttachmentEntityPaths(model, entity); + List paths = reader.getAttachmentEntityPaths(model, entity); + logger.debug("Found {} attachment entity paths", paths.size()); + return paths; } catch (Exception e) { + logger.error( + "Error getting attachment entity paths for {}: {}", + entity.getQualifiedName(), + e.getMessage(), + e); return new ArrayList<>(); } } @@ -70,6 +78,7 @@ public static List getAttachmentEntityPaths( */ public static Map getAttachmentPathMapping( CdsModel model, CdsEntity entity, PersistenceService persistenceService) { + logger.debug("Getting attachment path mapping for entity: {}", entity.getQualifiedName()); try { Map pathMapping = new HashMap<>(); SDMAssociationCascader cascader = new SDMAssociationCascader(); @@ -89,9 +98,10 @@ public static Map getAttachmentPathMapping( processNestedAttachmentComposition( model, entity, reader, pathMapping, composition)); + logger.debug("Found {} attachment path mappings for entity: {}", pathMapping.size(), entity.getQualifiedName()); return pathMapping; } catch (Exception e) { - logger.error(SDMUtils.getErrorMessage("FETCH_ATTACHMENT_COMPOSITION_ERROR"), e.getMessage()); + logger.error("Error fetching attachment composition for entity {}: {}", entity.getQualifiedName(), e.getMessage(), e); return new HashMap<>(); } } @@ -199,6 +209,7 @@ private static boolean isDirectAttachmentTargetAspect(String targetAspect) { */ public static List> fetchAttachments( String targetEntity, Map entity, String attachmentCompositionName) { + logger.debug("Fetching attachments for entity: {}, composition: {}", targetEntity, attachmentCompositionName); String[] targetEntityPath = targetEntity.split("\\."); targetEntity = targetEntityPath[targetEntityPath.length - 1]; entity = AttachmentsHandlerUtils.wrapEntityWithParent(entity, targetEntity); @@ -211,8 +222,10 @@ public static List> fetchAttachments( : null; // Second last part (e.g., "chapters") // Find all attachment arrays in the nested entity structure - return AttachmentsHandlerUtils.findNestedAttachments( + List> attachments = AttachmentsHandlerUtils.findNestedAttachments( entity, attachmentKeyFromComposition, parentKeyFromComposition); + logger.debug("Fetched {} attachments for composition: {}", attachments.size(), attachmentCompositionName); + return attachments; } private static List> findNestedAttachments( @@ -397,6 +410,7 @@ public static Map> getAttachmentCompositionDetails( PersistenceService persistenceService, String targetEntity, Map entityData) { + logger.debug("Getting attachment composition details for entity: {}", targetEntity); Map> attachmentDetails = new HashMap<>(); // Get the composition path mapping @@ -421,6 +435,7 @@ public static Map> getAttachmentCompositionDetails( attachmentDetails.put(definition, details); } + logger.debug("Found {} attachment composition details", attachmentDetails.size()); return attachmentDetails; } @@ -441,6 +456,7 @@ public static Map> getAttachmentCompositionDetails( */ public static Map getAttachmentParentTitles( String targetEntity, Map entity, Map compositionPathMapping) { + logger.debug("Getting parent titles for entity: {}", targetEntity); Map parentTitles = new HashMap<>(); String[] targetEntityPath = targetEntity.split("\\."); @@ -564,6 +580,7 @@ public static Boolean validateFileNames( String composition, String contextInfo, Optional attachmentEntity) { + logger.debug("Validating file names for composition: {}", composition); Boolean isError = false; String targetEntity = context.getTarget().getQualifiedName(); String upIdKey = ""; @@ -581,25 +598,28 @@ public static Boolean validateFileNames( // Collecting all the errors if (whitespaceFilenames != null && !whitespaceFilenames.isEmpty()) { + logger.warn("File name validation failed: whitespace-only filenames detected"); context .getMessages() .error(SDMUtils.getErrorMessage("FILENAME_WHITESPACE_ERROR_MESSAGE") + contextInfo); isError = true; } if (restrictedFileNames != null && !restrictedFileNames.isEmpty()) { + logger.warn("File name validation failed: restricted characters in {} files", restrictedFileNames.size()); context .getMessages() .error(SDMErrorMessages.nameConstraintMessage(restrictedFileNames) + contextInfo); isError = true; } if (duplicateFilenames != null && !duplicateFilenames.isEmpty()) { + logger.warn("File name validation failed: {} duplicate filenames found", duplicateFilenames.size()); String formattedMessage = String.format( "%s%s", SDMErrorMessages.duplicateFilenameFormat(duplicateFilenames), contextInfo); context.getMessages().error(formattedMessage); isError = true; } - // returning the error message + logger.debug("File name validation completed. Errors found: {}", isError); return isError; } @@ -616,7 +636,10 @@ public static Boolean validateFileNames( public static JSONObject fetchAttachmentDataFromSDM( SDMService sdmService, String objectId, SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { - return sdmService.getObject(objectId, sdmCredentials, isSystemUser); + logger.debug("Fetching attachment data from SDM for objectId: {}", objectId); + JSONObject result = sdmService.getObject(objectId, sdmCredentials, isSystemUser); + logger.debug("Successfully fetched attachment data from SDM for objectId: {}", objectId); + return result; } /** @@ -633,18 +656,23 @@ public static void updateFilenameProperty( String fileNameInSDM, Map updatedSecondaryProperties) throws ServiceException { + logger.debug("Updating filename property - DB: {}, Request: {}, SDM: {}", fileNameInDB, filenameInRequest, fileNameInSDM); if (fileNameInDB == null) { if (filenameInRequest != null) { if (!filenameInRequest.equals(fileNameInSDM)) { + logger.debug("Filename updated from SDM value: {} to request value: {}", fileNameInSDM, filenameInRequest); updatedSecondaryProperties.put("filename", filenameInRequest); } } else { + logger.warn("Filename validation failed: filename cannot be empty"); throw new ServiceException("Filename cannot be empty"); } } else { if (filenameInRequest == null) { + logger.warn("Filename validation failed: filename cannot be empty"); throw new ServiceException("Filename cannot be empty"); } else if (!fileNameInDB.equals(filenameInRequest)) { + logger.debug("Filename updated from DB value: {} to request value: {}", fileNameInDB, filenameInRequest); updatedSecondaryProperties.put("filename", filenameInRequest); } } @@ -657,6 +685,7 @@ public static void updateDescriptionProperty( Map updatedSecondaryProperties, Boolean isUpdate) throws ServiceException { + logger.debug("Updating description property - isUpdate: {}", isUpdate); // Normalize null to empty string for comparison String normalizedRequest = descriptionInRequest == null ? "" : descriptionInRequest; String normalizedDB = descriptionInDB == null ? "" : descriptionInDB; @@ -676,6 +705,7 @@ public static void updateDescriptionProperty( } } else if (!normalizedDB.equals( normalizedRequest)) { // Attachment contained description and is being updated now + logger.debug("Description updated from DB value to request value"); updatedSecondaryProperties.put("description", normalizedRequest); } } @@ -705,27 +735,32 @@ public static void handleSDMUpdateResponse( List noSDMRoles, List duplicateFileNameList, List filesNotFound) { + logger.debug("Handling SDM update response with code: {}", responseCode); switch (responseCode) { case 403: + logger.warn("SDM update failed with 403 Forbidden for file: {}", fileNameInSDM); noSDMRoles.add(fileNameInSDM); revertAttachmentProperties( attachment, fileNameInSDM, propertiesInDB, secondaryTypeProperties, descriptionInSDM); break; case 409: + logger.warn("SDM update failed with 409 Conflict (duplicate filename): {}", filenameInRequest); duplicateFileNameList.add(filenameInRequest); revertAttachmentProperties( attachment, fileNameInSDM, propertiesInDB, secondaryTypeProperties, descriptionInSDM); break; case 404: + logger.warn("SDM update failed with 404 Not Found for file: {}", fileNameInSDM); filesNotFound.add(fileNameInSDM); revertAttachmentProperties( attachment, fileNameInSDM, propertiesInDB, secondaryTypeProperties, descriptionInSDM); break; case 200: case 201: - // Success cases, do nothing + logger.debug("SDM update successful with response code: {}", responseCode); break; default: + logger.error("SDM update failed with unexpected response code: {}", responseCode); throw new ServiceException(SDMUtils.getErrorMessage("SDM_SERVER_ERROR"), (Object[]) null); } } @@ -753,6 +788,7 @@ public static void handleSDMServiceException( String descriptionInSDM, List filesWithUnsupportedProperties, Map badRequest) { + logger.error("SDM service exception occurred for file {}: {}", filenameInRequest, e.getMessage()); if (e.getMessage().startsWith(SDMUtils.getErrorMessage("UNSUPPORTED_PROPERTIES"))) { String unsupportedDetails = e.getMessage() @@ -783,6 +819,7 @@ public static void revertAttachmentProperties( Map propertiesInDB, Map secondaryTypeProperties, String descriptionInSDM) { + logger.debug("Reverting attachment properties for file: {}", fileName); if (propertiesInDB != null) { for (Map.Entry entry : propertiesInDB.entrySet()) { String dbKey = entry.getKey(); @@ -814,6 +851,7 @@ public static void revertAttachmentProperties( */ public static CmisDocument prepareCmisDocument( String filenameInRequest, String descriptionInRequest, String objectId) { + logger.debug("Preparing CMIS document - filename: {}, objectId: {}", filenameInRequest, objectId); CmisDocument cmisDocument = new CmisDocument(); cmisDocument.setFileName(filenameInRequest); cmisDocument.setDescription(descriptionInRequest); diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/SDMBeforeReadItemsModifier.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/SDMBeforeReadItemsModifier.java index 1c05b24c2..355408352 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/SDMBeforeReadItemsModifier.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/SDMBeforeReadItemsModifier.java @@ -24,15 +24,20 @@ public class SDMBeforeReadItemsModifier implements Modifier { public SDMBeforeReadItemsModifier(List mediaAssociations) { this.mediaAssociations = mediaAssociations; + logger.debug( + "Initialized SDMBeforeReadItemsModifier with {} media associations", + mediaAssociations.size()); } @Override public List items(List items) { + logger.debug("Modifying select items - input count: {}", items.size()); List newItems = new ArrayList<>(items.stream().filter(item -> !item.isExpand()).toList()); List result = addRequiredFields(items); newItems.addAll(result); + logger.debug("Modified select items - output count: {}", newItems.size()); return newItems; } @@ -47,6 +52,7 @@ private List addRequiredFields(List list) } private List processExpandedEntities(List expandedItems) { + logger.debug("Processing {} expanded entities", expandedItems.size()); List newItems = new ArrayList<>(); expandedItems.forEach( diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMApplicationHandlerHelper.java b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMApplicationHandlerHelper.java index 6bb0824a0..5d8d692d3 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMApplicationHandlerHelper.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMApplicationHandlerHelper.java @@ -1,12 +1,15 @@ package com.sap.cds.sdm.handler.common; import com.sap.cds.reflect.CdsStructuredType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The class {@link SDMApplicationHandlerHelper} provides helper methods for the SDM attachment * application handlers. */ public final class SDMApplicationHandlerHelper { + private static final Logger logger = LoggerFactory.getLogger(SDMApplicationHandlerHelper.class); private static final String ANNOTATION_IS_MEDIA_DATA = "_is_media_data"; /** @@ -17,7 +20,9 @@ public final class SDMApplicationHandlerHelper { * @return true if the entity is a media entity, false otherwise */ public static boolean isMediaEntity(CdsStructuredType baseEntity) { - return baseEntity.getAnnotationValue(ANNOTATION_IS_MEDIA_DATA, false); + boolean isMedia = baseEntity.getAnnotationValue(ANNOTATION_IS_MEDIA_DATA, false); + logger.debug("Entity {} isMediaEntity: {}", baseEntity.getQualifiedName(), isMedia); + return isMedia; } private SDMApplicationHandlerHelper() { diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAssociationCascader.java b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAssociationCascader.java index 48e8c2734..484f548e7 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAssociationCascader.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAssociationCascader.java @@ -10,6 +10,8 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The class {@link SDMAssociationCascader} is used to find entity paths to all media resource @@ -18,7 +20,10 @@ */ public class SDMAssociationCascader { + private static final Logger logger = LoggerFactory.getLogger(SDMAssociationCascader.class); + public SDMNodeTree findEntityPath(CdsModel model, CdsEntity entity) { + logger.debug("Finding entity path for: {}", entity.getQualifiedName()); var firstList = new LinkedList(); var internalResultList = getAttachmentAssociationPath( @@ -26,6 +31,8 @@ public SDMNodeTree findEntityPath(CdsModel model, CdsEntity entity) { var rootTree = new SDMNodeTree(new SDMAssociationIdentifier("", entity.getQualifiedName())); internalResultList.forEach(rootTree::addPath); + logger.debug( + "Found {} paths for entity: {}", internalResultList.size(), entity.getQualifiedName()); return rootTree; } @@ -42,6 +49,7 @@ private List> getAttachmentAssociationPath( var isMediaEntity = SDMApplicationHandlerHelper.isMediaEntity(entity); if (isMediaEntity) { + logger.debug("Found media entity: {}", entity.getQualifiedName()); var identifier = new SDMAssociationIdentifier(associationName, entity.getQualifiedName()); firstList.addLast(identifier); } @@ -64,9 +72,15 @@ private List> getAttachmentAssociationPath( element -> element.getType().as(CdsAssociationType.class).getTarget())); if (associations.isEmpty()) { + logger.debug("No composition associations found for entity: {}", entity.getQualifiedName()); return internalResultList; } + logger.debug( + "Processing {} composition associations for entity: {}", + associations.size(), + entity.getQualifiedName()); + var newListNeeded = false; for (var associatedElement : associations.entrySet()) { if (!processedEntities.contains(associatedElement.getValue().getQualifiedName())) { diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java index 1164cdf23..b35500c2d 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java @@ -14,6 +14,8 @@ import com.sap.cds.services.persistence.PersistenceService; import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The class {@link SDMAttachmentsReader} is used to deep read attachments from the database for a @@ -24,36 +26,47 @@ */ public class SDMAttachmentsReader { + private static final Logger logger = LoggerFactory.getLogger(SDMAttachmentsReader.class); private final SDMAssociationCascader cascader; private final PersistenceService persistence; public SDMAttachmentsReader(SDMAssociationCascader cascader, PersistenceService persistence) { this.cascader = requireNonNull(cascader, "cascader must not be null"); this.persistence = requireNonNull(persistence, "persistence must not be null"); + logger.debug("SDMAttachmentsReader initialized"); } public List readAttachments( CdsModel model, CdsEntity entity, CqnFilterableStatement statement) { + logger.debug("START: Reading attachments for entity: {}", entity.getQualifiedName()); SDMNodeTree nodePath = cascader.findEntityPath(model, entity); List> expandList = buildExpandList(nodePath); + logger.debug("Found {} expand nodes for attachment path", expandList.size()); Select select; if (!expandList.isEmpty()) { + logger.debug("Building query with expand list for deep read"); select = Select.from(statement.ref()).columns(expandList); } else { + logger.debug("Building query without expand list"); select = Select.from(statement.ref()).columns(StructuredType::_all); } if (statement.where().isPresent()) { select.where(statement.where().get()); + logger.debug("Query includes where clause"); } Result result = persistence.run(select); - return result.listOf(Attachments.class); + List attachmentsList = result.listOf(Attachments.class); + logger.info("Read {} attachments for entity: {}", attachmentsList.size(), entity.getQualifiedName()); + logger.debug("END: Reading attachments"); + return attachmentsList; } public List getAttachmentEntityPaths(CdsModel model, CdsEntity entity) { + logger.debug("Getting attachment entity paths for: {}", entity.getQualifiedName()); SDMNodeTree nodePath = cascader.findEntityPath(model, entity); List attachmentPaths = new ArrayList<>(); @@ -61,15 +74,18 @@ public List getAttachmentEntityPaths(CdsModel model, CdsEntity entity) { if (nodePath != null) { collectAttachmentPaths(nodePath, attachmentPaths, model); } + logger.debug("Found {} attachment entity paths", attachmentPaths.size()); return attachmentPaths; } private void collectAttachmentPaths( SDMNodeTree node, List attachmentPaths, CdsModel model) { String entityName = node.getIdentifier().fullEntityName(); + logger.debug("Checking entity: {}", entityName); // Check if this entity is an attachment entity if (isAttachmentEntity(model, entityName)) { + logger.debug("Found attachment entity: {}", entityName); attachmentPaths.add(entityName); } @@ -82,22 +98,31 @@ private void collectAttachmentPaths( private boolean isAttachmentEntity(CdsModel model, String entityName) { var entityOpt = model.findEntity(entityName); if (!entityOpt.isPresent()) { + logger.debug("Entity not found in model: {}", entityName); return false; } CdsEntity entity = entityOpt.get(); // Check if this entity has the @_is_media_data annotation (indicating attachment entity) - return entity.getAnnotationValue("_is_media_data", false); + boolean isMediaData = entity.getAnnotationValue("_is_media_data", false); + logger.debug("Entity {} is media entity: {}", entityName, isMediaData); + return isMediaData; } private List> buildExpandList(SDMNodeTree root) { List> expandResultList = new ArrayList<>(); + if (root == null) { + logger.debug("Root node is null, returning empty expand list"); + return expandResultList; + } + root.getChildren() .forEach( child -> { Expand expand = buildExpandFromTree(child); expandResultList.add(expand); }); + logger.debug("Built expand list with {} items", expandResultList.size()); return expandResultList; } diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMNodeTree.java b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMNodeTree.java index 71611bef2..0a12d00da 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMNodeTree.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMNodeTree.java @@ -3,6 +3,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The class {@link SDMNodeTree} is a tree data structure that holds the SDM association identifier @@ -10,6 +12,8 @@ */ class SDMNodeTree { + private static final Logger logger = LoggerFactory.getLogger(SDMNodeTree.class); + private final SDMAssociationIdentifier identifier; private final List children = new ArrayList<>(); @@ -18,11 +22,13 @@ class SDMNodeTree { } void addPath(List path) { + logger.debug("Adding path with {} identifiers to node: {}", path.size(), identifier); var currentIdentifierOptional = path.stream() .filter(entry -> entry.fullEntityName().equals(identifier.fullEntityName())) .findAny(); if (currentIdentifierOptional.isEmpty()) { + logger.debug("Current identifier not found in path, skipping"); return; } var currentNode = this; @@ -42,8 +48,10 @@ private SDMNodeTree getChildOrNew(SDMAssociationIdentifier identifier) { .filter(child -> child.identifier.fullEntityName().equals(identifier.fullEntityName())) .findAny(); if (childOptional.isPresent()) { + logger.debug("Found existing child node: {}", identifier.fullEntityName()); return childOptional.get(); } else { + logger.debug("Creating new child node: {}", identifier.fullEntityName()); SDMNodeTree child = new SDMNodeTree(identifier); children.add(child); return child; diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java b/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java index 98e001d38..4c608f589 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java @@ -58,25 +58,41 @@ public JSONObject createDocument( boolean isSystemUser, AttachmentCreateEventContext eventContext) throws IOException { + long startTime = System.currentTimeMillis(); + logger.info("START: Create document - fileName: {}, fileSize: {} bytes", + cmisDocument.getFileName(), cmisDocument.getContentLength()); + logger.debug("Document properties - repositoryId: {}, mimeType: {}", + cmisDocument.getRepositoryId(), cmisDocument.getMimeType()); + try { if ("application/internet-shortcut".equalsIgnoreCase(cmisDocument.getMimeType())) { logger.info("LinkType detected, uploading as single chunk"); - return uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); + JSONObject result = uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); + logger.info("Link file uploaded successfully in {} ms", (System.currentTimeMillis() - startTime)); + return result; } long totalSize = cmisDocument.getContentLength(); int chunkSize = SDMConstants.CHUNK_SIZE; cmisDocument.setUploadStatus(SDMConstants.UPLOAD_STATUS_IN_PROGRESS); + logger.debug("Total file size: {} bytes, Chunk size: {} bytes", totalSize, chunkSize); + if (totalSize <= 400 * 1024 * 1024) { - // Upload directly if file is ≤ 400MB - return uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); + logger.info("File size is <= 400MB, uploading as single chunk"); + JSONObject result = uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); + logger.info("File uploaded successfully as single chunk in {} ms", (System.currentTimeMillis() - startTime)); + return result; } else { String sdmUrl = sdmCredentials.getUrl() + "browser/" + cmisDocument.getRepositoryId() + "/root"; // Upload in chunks if file is > 400MB - return uploadLargeFileInChunks(cmisDocument, sdmUrl, chunkSize, isSystemUser); + logger.info("File size is > 400MB, uploading in chunks of {} bytes", chunkSize); + JSONObject result = uploadLargeFileInChunks(cmisDocument, sdmUrl, chunkSize, isSystemUser); + logger.info("File uploaded successfully in chunks in {} ms", (System.currentTimeMillis() - startTime)); + return result; } } catch (Exception e) { + logger.error("Error uploading document: {}", e.getMessage(), e); throw new IOException("Error uploading document: " + e.getMessage(), e); } } @@ -87,8 +103,10 @@ private void executeHttpPost( CmisDocument cmisDocument, Map finalResponse) throws ServiceException { + logger.debug("START: executeHttpPost for file: {}", cmisDocument.getFileName()); try (CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(uploadFile)) { formResponse(cmisDocument, finalResponse, response); + logger.debug("END: executeHttpPost - response formed for file: {}", cmisDocument.getFileName()); } catch (IOException e) { throw new ServiceException(SDMUtils.getErrorMessage("ERROR_IN_SETTING_TIMEOUT"), e); } @@ -107,6 +125,9 @@ private JSONObject appendContentStream( boolean isSystemUser) throws IOException, ParseException { + long startTime = System.currentTimeMillis(); + logger.debug("Appending chunk {} with {} bytes, isLastChunk: {}", chunkIndex, bytesRead, isLastChunk); + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addTextBody("cmisaction", "appendContent"); builder.addTextBody("objectId", cmisDocument.getObjectId()); @@ -136,15 +157,18 @@ private JSONObject appendContentStream( try { this.executeHttpPost(httpClient, request, cmisDocument, finalResponse); cmisDocument.setMimeType(finalResponse.get("mimeType")); + long duration = System.currentTimeMillis() - startTime; + logger.debug("Chunk {} appended successfully in {} ms", chunkIndex, duration); return new JSONObject(finalResponse); } catch (Exception e) { - logger.error("Error in appending content: {}", e.getMessage()); + logger.error("Error appending chunk {}: {}", chunkIndex, e.getMessage(), e); throw new IOException("Error in appending content: " + e.getMessage(), e); } } private JSONObject createEmptyDocument( CmisDocument cmisDocument, String sdmUrl, boolean isSystemUser) { + logger.debug("START: createEmptyDocument for file: {}", cmisDocument.getFileName()); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addTextBody("cmisaction", "createDocument"); @@ -164,6 +188,7 @@ private JSONObject createEmptyDocument( Map finalResponse = new HashMap<>(); executeHttpPost(httpClient, request, cmisDocument, finalResponse); + logger.debug("END: createEmptyDocument - empty document created for file: {}", cmisDocument.getFileName()); return new JSONObject(finalResponse); } @@ -171,6 +196,7 @@ private JSONObject createEmptyDocument( public JSONObject uploadSingleChunk( CmisDocument cmisDocument, SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { + logger.debug("START: uploadSingleChunk for file: {}", cmisDocument.getFileName()); InputStream originalStream = cmisDocument.getContent(); if (!cmisDocument.getMimeType().equalsIgnoreCase("application/internet-shortcut") @@ -214,6 +240,7 @@ public JSONObject uploadSingleChunk( Map finalResMap = new HashMap<>(); executeHttpPost(httpClient, request, cmisDocument, finalResMap); + logger.debug("END: uploadSingleChunk - file uploaded: {}", cmisDocument.getFileName()); return new JSONObject(finalResMap); } @@ -221,6 +248,7 @@ public JSONObject uploadSingleChunk( private JSONObject uploadLargeFileInChunks( CmisDocument cmisDocument, String sdmUrl, int chunkSize, boolean isSystemUser) throws IOException { + logger.debug("START: uploadLargeFileInChunks for file: {}, chunkSize: {}", cmisDocument.getFileName(), chunkSize); try (ReadAheadInputStream chunkedStream = new ReadAheadInputStream(cmisDocument.getContent(), cmisDocument.getContentLength())) { @@ -309,6 +337,7 @@ private JSONObject uploadLargeFileInChunks( hasMoreChunks = false; } } + logger.debug("END: uploadLargeFileInChunks - completed {} chunks for file: {}", chunkIndex, cmisDocument.getFileName()); return responseBody; } catch (Exception e) { logger.error("Exception in uploadLargeFileInChunks: {}", e.getMessage()); @@ -321,6 +350,7 @@ private void formResponse( CmisDocument cmisDocument, Map finalResponse, CloseableHttpResponse response) { + logger.debug("START: formResponse for file: {}", cmisDocument.getFileName()); String status = "success"; String name = cmisDocument.getFileName(); String id = cmisDocument.getAttachmentId(); @@ -329,7 +359,10 @@ private void formResponse( try { String responseString = EntityUtils.toString(response.getEntity()); int responseCode = response.getStatusLine().getStatusCode(); + logger.debug("SDM response code: {} for file: {}", responseCode, name); + if (responseCode == 201 || responseCode == 200) { + logger.info("Document created successfully with response code: {}", responseCode); JSONObject jsonResponse = new JSONObject(responseString); JSONObject succinctProperties = jsonResponse.getJSONObject("succinctProperties"); status = "success"; @@ -342,28 +375,37 @@ private void formResponse( succinctProperties.has("cmis:contentStreamMimeType") ? succinctProperties.getString("cmis:contentStreamMimeType") : null; + logger.debug("objectId: {}, scanStatus: {}, mimeType: {}", objectId, scanStatus, mimeType); } else { if (responseCode == 409) { + logger.warn("Conflict response code 409 for file: {}", name); JSONObject jsonResponse = new JSONObject(responseString); String message = jsonResponse.getString("message"); if ("Malware Service Exception: Virus found in the file!".equals(message)) { status = "virus"; + logger.warn("Virus detected in file: {}", name); } else { status = "duplicate"; + logger.warn("Duplicate file detected: {}", name); } } else if ((responseCode == 403) && (responseString.equals("User does not have required scope"))) { status = "unauthorized"; + logger.warn("User unauthorized - missing required scope"); } else if (responseCode == 403) { JSONObject jsonResponse = new JSONObject(responseString); String message = jsonResponse.getString("message"); if ("MIME type of the uploaded file is blocked according to your repository configuration." - .equals(message)) status = "blocked"; + .equals(message)) { + status = "blocked"; + logger.warn("MIME type blocked for file: {}", name); + } } else { JSONObject jsonResponse = new JSONObject(responseString); String message = jsonResponse.getString("message"); status = "fail"; error = message; + logger.error("Document upload failed with response code {} : {}", responseCode, error); } } // Construct the final response @@ -381,18 +423,23 @@ private void formResponse( switch (scanStatusEnum) { case QUARANTINED: uploadStatus = SDMConstants.UPLOAD_STATUS_VIRUS_DETECTED; + logger.warn("Virus scan status: QUARANTINED for file: {}", name); break; case SCANNING: uploadStatus = SDMConstants.VIRUS_SCAN_INPROGRESS; + logger.info("Virus scan in progress for file: {}", name); break; case FAILED: uploadStatus = SDMConstants.UPLOAD_STATUS_SCAN_FAILED; + logger.warn("Virus scan failed for file: {}", name); break; case CLEAN: uploadStatus = SDMConstants.UPLOAD_STATUS_SUCCESS; + logger.info("File is clean: {}", name); break; case PENDING: uploadStatus = SDMConstants.UPLOAD_STATUS_IN_PROGRESS; + logger.info("Virus scan pending for file: {}", name); break; case BLANK: default: @@ -401,7 +448,9 @@ private void formResponse( } finalResponse.put("uploadStatus", uploadStatus); } + logger.debug("END: formResponse - status: {} for file: {}", status, name); } catch (IOException e) { + logger.error("Error forming response: {}", e.getMessage(), e); throw new ServiceException( SDMErrorMessages.getGenericError(SDMUtils.getErrorMessage("EVENT_UPLOAD")), e); } diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java b/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java index 67f5e1b86..65f6bd257 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java @@ -45,6 +45,7 @@ public boolean isChunkQueueEmpty() { } private void preloadChunks() { + logger.debug("START: preloadChunks - totalSize: {}", totalSize); executor.submit( () -> { try { @@ -90,6 +91,7 @@ private void preloadChunks() { private void readChunk(AtomicReference bufferRef, AtomicLong bytesReadAtomic) throws IOException { + logger.debug("START: readChunk"); int maxRetries = 5; int retryCount = 0; @@ -177,8 +179,10 @@ public synchronized long getRemainingBytes() { } private synchronized void loadNextChunk() throws IOException { + logger.debug("START: loadNextChunk"); try { if (chunkQueue.isEmpty() && lastChunkLoaded.get()) { + logger.debug("END: loadNextChunk - no more data"); return; // No more data, return EOF } @@ -190,6 +194,7 @@ private synchronized void loadNextChunk() throws IOException { if (lastChunkLoaded.get() && chunkQueue.isEmpty()) { logger.info(" Last chunk successfully processed and uploaded."); } + logger.debug("END: loadNextChunk - loaded {} bytes", currentBufferSize); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException(" Interrupted while loading next chunk ", e); @@ -211,6 +216,7 @@ public synchronized int read() throws IOException { @Override public synchronized int read(byte[] b, int off, int len) throws IOException { + logger.debug("read(byte[], off={}, len={}) called, position: {}, bufferSize: {}", off, len, position.get(), currentBufferSize); if (position.get() >= currentBufferSize) { if (lastChunkLoaded.get()) return -1; loadNextChunk(); @@ -224,6 +230,7 @@ public synchronized int read(byte[] b, int off, int len) throws IOException { off, bytesToRead); // Read the input stream byte array into the buffer position.addAndGet(bytesToRead); + logger.debug("read(byte[]) returning {} bytes", bytesToRead); return bytesToRead; } @@ -246,6 +253,7 @@ public void close() throws IOException { throw new IOException(" Error shutting down executor", e); } originalStream.close(); + logger.debug("END: close - stream closed"); } public synchronized void resetStream() throws IOException { diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/RetryUtils.java b/sdm/src/main/java/com/sap/cds/sdm/service/RetryUtils.java index 78ffdffec..76f76e856 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/RetryUtils.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/RetryUtils.java @@ -24,6 +24,7 @@ private RetryUtils() { private static final Logger logger = LoggerFactory.getLogger(RetryUtils.class); public static Predicate shouldRetry() { + logger.debug("START: shouldRetry predicate created"); return throwable -> { logger.info("Evaluating shouldRetry for: {}", throwable.toString()); @@ -42,11 +43,13 @@ public static Predicate shouldRetry() { } cause = cause.getCause(); } + logger.debug("No retryable exception found, returning false"); return false; }; } public static Function, Publisher> retryLogic(int maxAttempts) { + logger.debug("START: retryLogic with maxAttempts: {}", maxAttempts); return errors -> errors .zipWith( diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java index c3dc706a0..aaf8e3cfe 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java @@ -38,6 +38,7 @@ public class SDMAdminServiceImpl implements SDMAdminService { @java.lang.Override public String onboardRepository(Repository repository) throws JsonProcessingException, UnsupportedEncodingException { + logger.debug("START: onboardRepository for repository: {}", repository != null ? repository.getDisplayName() : "null"); if (repository == null) { logger.error("Repository object is null. Cannot proceed with onboarding."); throw new IllegalArgumentException("Repository object cannot be null."); @@ -144,6 +145,7 @@ public String onboardRepository(Repository repository) repository.getDisplayName()) + " : " + e.getMessage()); + logger.debug("END: onboardRepository - failed with exception"); throw new ServiceException( String.format( SDMUtils.getErrorMessage("ONBOARD_REPO_ERROR_MESSAGE"), repository.getDisplayName()), @@ -153,6 +155,7 @@ public String onboardRepository(Repository repository) @java.lang.Override public String offboardRepository(String subdomain) { + logger.debug("START: offboardRepository for subdomain: {}", subdomain); SDMCredentials sdmCredentials; try { sdmCredentials = tokenHandler.getSDMCredentials(); @@ -257,6 +260,7 @@ public String offboardRepository(String subdomain) { } logger.info("Repository " + repoId + " Offboarded"); + logger.debug("END: offboardRepository - success"); return "Repository " + repoId + " Offboarded"; } catch (IOException e) { logger.error("Error while offboarding repository: " + e.getMessage()); @@ -269,6 +273,7 @@ public String offboardRepository(String subdomain) { } private String getRepositoryId(String jsonString) { + logger.debug("START: getRepositoryId"); ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode rootNode = objectMapper.readTree(jsonString); @@ -284,6 +289,7 @@ private String getRepositoryId(String jsonString) { for (JsonNode repoInfo : repoInfos) { JsonNode repository = repoInfo.path("repository"); if (repository.path("externalId").asText().equals(SDMConstants.REPOSITORY_ID)) { + logger.debug("END: getRepositoryId - found: {}", repository.path("id").asText()); return repository.path("id").asText(); } } @@ -291,6 +297,7 @@ private String getRepositoryId(String jsonString) { throw new ServiceException( SDMUtils.getErrorMessage("FAILED_TO_PARSE_REPOSITORY_RESPONSE"), e); } + logger.debug("END: getRepositoryId - not found"); return null; } } 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 57ff98578..32577f009 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 @@ -35,6 +35,7 @@ public SDMAttachmentsService() { @Override public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser) { + logger.debug("START: copyAttachments"); logger.info( "Copying attachments for upId: {}, facet: {}, objectIds: {}, isSystemUser: {}", input.upId(), @@ -62,10 +63,12 @@ public void copyAttachments(CopyAttachmentInput input, boolean isSystemUser) { copyContext.setSystemUser(isSystemUser); emit(copyContext); + logger.debug("END: copyAttachments - event emitted"); } @Override public Map moveAttachments(MoveAttachmentInput input, boolean isSystemUser) { + logger.debug("START: moveAttachments"); logger.info( "Moving attachments from sourceFolderId: {} (sourceFacet: {}) to upId: {}, targetFacet:" + " {}, objectIds: {}, isSystemUser: {}", @@ -137,11 +140,14 @@ public Map moveAttachments(MoveAttachmentInput input, boolean is // Return structured result that OData can serialize Map result = new HashMap<>(); result.put("failedAttachments", failedAttachments != null ? failedAttachments : List.of()); + logger.debug("END: moveAttachments - returning result with {} failed attachments", + failedAttachments != null ? failedAttachments.size() : 0); return result; } @Override public InputStream readAttachment(String contentId) { + logger.debug("START: readAttachment for contentId: {}", contentId); logger.info("Reading attachment with document id: {}", contentId); var readContext = AttachmentReadEventContext.create(); @@ -150,11 +156,13 @@ public InputStream readAttachment(String contentId) { emit(readContext); + logger.debug("END: readAttachment - returning content stream"); return readContext.getData().getContent(); } @Override public AttachmentModificationResult createAttachment(CreateAttachmentInput input) { + logger.debug("START: createAttachment"); logger.info( "Creating attachment for entity name: {}", input.attachmentEntity().getQualifiedName()); var createContext = AttachmentCreateEventContext.create(); @@ -168,6 +176,7 @@ public AttachmentModificationResult createAttachment(CreateAttachmentInput input emit(createContext); + logger.debug("END: createAttachment - contentId: {}", createContext.getContentId()); return new AttachmentModificationResult( Boolean.TRUE.equals(createContext.getIsInternalStored()), createContext.getContentId(), @@ -176,6 +185,7 @@ public AttachmentModificationResult createAttachment(CreateAttachmentInput input @Override public void markAttachmentAsDeleted(MarkAsDeletedInput input) { + logger.debug("START: markAttachmentAsDeleted"); logger.info("Marking attachment as deleted for document id in SDM{}", input.contentId()); var deleteContext = AttachmentMarkAsDeletedEventContext.create(); @@ -183,15 +193,18 @@ public void markAttachmentAsDeleted(MarkAsDeletedInput input) { deleteContext.setDeletionUserInfo(fillDeletionUserInfo(input.userInfo())); emit(deleteContext); + logger.debug("END: markAttachmentAsDeleted - event emitted"); } @Override public void restoreAttachment(Instant restoreTimestamp) { + logger.debug("START: restoreAttachment"); logger.info("Restoring deleted attachment for timestamp: {}", restoreTimestamp); var restoreContext = AttachmentRestoreEventContext.create(); restoreContext.setRestoreTimestamp(restoreTimestamp); emit(restoreContext); + logger.debug("END: restoreAttachment - event emitted"); } private DeletionUserInfo fillDeletionUserInfo(UserInfo userInfo) { diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMPropertySupplier.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMPropertySupplier.java index e3c607518..c21dfc200 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMPropertySupplier.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMPropertySupplier.java @@ -7,8 +7,11 @@ import io.reactivex.annotations.NonNull; import java.net.URI; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class SDMPropertySupplier extends DefaultOAuth2PropertySupplier { + private static final Logger logger = LoggerFactory.getLogger(SDMPropertySupplier.class); public SDMPropertySupplier(ServiceBindingDestinationOptions options) { super(options); @@ -17,15 +20,20 @@ public SDMPropertySupplier(ServiceBindingDestinationOptions options) { @NonNull @Override public URI getServiceUri() { - return getCredentialOrThrow(URI.class, "endpoints", "ecmservice", "url"); + logger.debug("START: getServiceUri"); + URI uri = getCredentialOrThrow(URI.class, "endpoints", "ecmservice", "url"); + logger.debug("END: getServiceUri - returning: {}", uri); + return uri; } @NotNull @Override public OAuth2Options getOAuth2Options() { + logger.debug("START: getOAuth2Options"); var builder = OAuth2Options.builder(); var user = this.options.getOption(SDMUser.class); if (!user.isEmpty()) { + logger.debug("User option present, adding X-EcmUserEnc and X-EcmAddPrincipals attributes"); var objectMapper = new ObjectMapper(); var azAttrNode = objectMapper.createObjectNode(); // add X-EcmUserEnc attribute @@ -37,6 +45,7 @@ public OAuth2Options getOAuth2Options() { authoritiesNode.set("az_attr", azAttrNode); builder.withTokenRetrievalParameter("authorities", authoritiesNode.toString()); } + logger.debug("END: getOAuth2Options"); return builder.build(); } } 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 56a37ce6a..bb7cea4e3 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 @@ -51,11 +51,13 @@ public SDMServiceImpl( this.connectionPool = connectionPool; this.binding = binding; this.tokenHandler = tokenHandler; + logger.info("SDMServiceImpl initialized"); } @Override public JSONObject createDocument( CmisDocument cmisDocument, SDMCredentials sdmCredentials, String jwtToken) { + logger.debug("START: createDocument for file: {}", cmisDocument.getFileName()); var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, NAMED_USER_FLOW); Map finalResponse = new HashMap<>(); String sdmUrl = sdmCredentials.getUrl() + "browser/" + cmisDocument.getRepositoryId() + "/root"; @@ -78,6 +80,7 @@ public JSONObject createDocument( HttpEntity multipart = builder.build(); uploadFile.setEntity(multipart); executeHttpPost(httpClient, uploadFile, cmisDocument, finalResponse); + logger.debug("END: createDocument - status: {}", finalResponse.get("status")); return new JSONObject(finalResponse); } @@ -85,6 +88,7 @@ public JSONObject createDocument( public JSONObject editLink( CmisDocument cmisDocument, SDMCredentials sdmCredentials, boolean isSystemUser) throws ServiceException { + logger.debug("START: editLink for objectId: {}", cmisDocument.getObjectId()); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, grantType); @@ -118,6 +122,7 @@ public JSONObject editLink( uploadFile.setEntity(multipart); executeHttpPost(httpClient, uploadFile, cmisDocument, finalResponse); + logger.debug("END: editLink - status: {}", finalResponse.get("status")); return new JSONObject(finalResponse); } @@ -194,6 +199,7 @@ public int updateAttachments( Map secondaryPropertiesWithInvalidDefinitions, boolean isSystemUser) throws ServiceException { + logger.debug("START: updateAttachments for objectId: {}", cmisDocument.getObjectId()); String repositoryId = SDMConstants.REPOSITORY_ID; String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); @@ -302,6 +308,7 @@ public int updateAttachments( // Only proceed with the update if there are properties to update if (updateRequestBody.isEmpty()) { + logger.debug("END: updateAttachments - no updates needed"); return 200; // No updates needed, return success } @@ -319,8 +326,10 @@ public int updateAttachments( String message = jsonResponse.getString("message"); throw new ServiceException(message); } + logger.debug("END: updateAttachments - status: {}", response.getStatusLine().getStatusCode()); return response.getStatusLine().getStatusCode(); } catch (IOException e) { + logger.error("Error updating attachments: {}", e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("COULD_NOT_UPDATE_THE_ATTACHMENT"), e); } } @@ -328,6 +337,7 @@ public int updateAttachments( @Override public JSONObject getObject(String objectId, SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { + logger.debug("START: getObject for objectId: {}", objectId); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, grantType); @@ -349,8 +359,10 @@ public JSONObject getObject(String objectId, SDMCredentials sdmCredentials, bool return null; } String responseString = EntityUtils.toString(response.getEntity()); + logger.debug("END: getObject - retrieved successfully"); return new JSONObject(responseString); } catch (IOException e) { + logger.error("Error getting object {}: {}", objectId, e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("ATTACHMENT_NOT_FOUND"), e); } } @@ -358,6 +370,7 @@ public JSONObject getObject(String objectId, SDMCredentials sdmCredentials, bool @Override public void readDocument( String objectId, SDMCredentials sdmCredentials, AttachmentReadEventContext context) { + logger.debug("START: readDocument for objectId: {}", objectId); String repositoryId = SDMConstants.REPOSITORY_ID; String grantType = context.getUserInfo().isSystemUser() ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); @@ -384,8 +397,10 @@ public void readDocument( byte[] responseBody = EntityUtils.toByteArray(response.getEntity()); try (InputStream inputStream = new ByteArrayInputStream(responseBody)) { context.getData().setContent(inputStream); + logger.debug("END: readDocument - content set in context"); } } catch (Exception e) { + logger.error("Error reading document {}: {}", objectId, e.getMessage(), e); throw new ServiceException("Failed to set document stream in context"); } } @@ -440,6 +455,7 @@ public String getFolderId( PersistenceService persistenceService, String folderName, boolean isSystemUser) { + logger.debug("START: getFolderId for folderName: {}", folderName); @SuppressWarnings("unchecked") List> resultList = @@ -457,6 +473,7 @@ public String getFolderId( // continue if (repoId.equalsIgnoreCase(repositoryId)) { folderId = attachment.get("folderId").toString(); + logger.debug("Found folderId in result: {}", folderId); break; } } @@ -465,22 +482,27 @@ public String getFolderId( SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); if (folderId == null) { + logger.debug("FolderId not found in result, trying to get by path"); folderId = getFolderIdByPath(folderName, SDMConstants.REPOSITORY_ID, sdmCredentials, isSystemUser); if (folderId == null) { + logger.info("Folder path not found, creating new folder: {}", folderName); folderId = createFolder(folderName, SDMConstants.REPOSITORY_ID, sdmCredentials, isSystemUser); JSONObject jsonObject = new JSONObject(folderId); JSONObject succinctProperties = jsonObject.getJSONObject("succinctProperties"); folderId = succinctProperties.getString("cmis:objectId"); + logger.info("Folder created with ID: {}", folderId); } } + logger.debug("END: getFolderId - returning folderId: {}", folderId); return folderId; } @Override public String getFolderIdByPath( String parentId, String repositoryId, SDMCredentials sdmCredentials, boolean isSystemUser) { + logger.debug("START: getFolderIdByPath for parentId: {}", parentId); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); String folderId = null; @@ -505,6 +527,7 @@ public String getFolderIdByPath( } else if (responseCode == 403) { throw new ServiceException(SDMUtils.getErrorMessage("USER_NOT_AUTHORISED_ERROR")); } + logger.debug("END: getFolderIdByPath - folderId: {}", folderId); return folderId; } catch (IOException e) { throw new ServiceException( @@ -515,6 +538,7 @@ public String getFolderIdByPath( @Override public String createFolder( String parentId, String repositoryId, SDMCredentials sdmCredentials, boolean isSystemUser) { + logger.debug("START: createFolder for parentId: {}", parentId); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, grantType); @@ -533,8 +557,10 @@ public String createFolder( try (var response = (CloseableHttpResponse) httpClient.execute(createFolderRequest)) { int responseCode = response.getStatusLine().getStatusCode(); String responseBody = EntityUtils.toString(response.getEntity()); - if (responseCode == 201) return responseBody; - else if (responseCode == 403) { + if (responseCode == 201) { + logger.debug("END: createFolder - folder created successfully"); + return responseBody; + } else if (responseCode == 403) { throw new ServiceException(SDMUtils.getErrorMessage("USER_NOT_AUTHORISED_ERROR")); } else { throw new ServiceException( @@ -548,11 +574,13 @@ else if (responseCode == 403) { @Override public RepoValue checkRepositoryType(String repositoryId, String tenant) { + logger.debug("Checking repository type for repositoryId: {}, tenant: {}", repositoryId, tenant); RepoKey repoKey = new RepoKey(); repoKey.setSubdomain(tenant); repoKey.setRepoId(repositoryId); RepoValue repoValue = CacheConfig.getRepoCache().get(repoKey); if (repoValue == null) { + logger.debug("Repository info not in cache, fetching from SDM"); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); JSONObject repoInfo = getRepositoryInfo(sdmCredentials); Map repoValueMap = fetchRepositoryData(repoInfo, repositoryId); @@ -560,14 +588,18 @@ public RepoValue checkRepositoryType(String repositoryId, String tenant) { repoKey.setSubdomain(tenant); repoKey.setRepoId(repositoryId); RepoValue value = repoValueMap.get(repositoryId); + logger.debug("Repository info fetched - VersionEnabled: {}, VirusScanEnabled: {}", + value.getVersionEnabled(), value.getVirusScanEnabled()); CacheConfig.getRepoCache().put(repoKey, value); return repoValueMap.get(repositoryId); } + logger.debug("Repository info found in cache"); return repoValue; } @Override public JSONObject getRepositoryInfo(SDMCredentials sdmCredentials) { + logger.debug("Fetching repository information from SDM"); String repositoryId = SDMConstants.REPOSITORY_ID; var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, TECHNICAL_USER_FLOW); @@ -576,18 +608,23 @@ public JSONObject getRepositoryInfo(SDMCredentials sdmCredentials) { HttpGet getRepoInfoRequest = new HttpGet(getRepoInfoUrl); try (var response = (CloseableHttpResponse) httpClient.execute(getRepoInfoRequest)) { if (response.getStatusLine().getStatusCode() != 200) { + logger.error("Failed to fetch repository info. Status code: {}", response.getStatusLine().getStatusCode()); throw new ServiceException(SDMUtils.getErrorMessage("REPOSITORY_ERROR")); } String responseString = EntityUtils.toString(response.getEntity()); + logger.debug("Repository information fetched successfully"); return new JSONObject(responseString); } catch (IOException e) { + logger.error("Error fetching repository info: {}", e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("REPOSITORY_ERROR"), e); } catch (Exception e) { + logger.error("Unexpected error fetching repository info: {}", e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("REPOSITORY_ERROR"), e); } } public Map fetchRepositoryData(JSONObject repoInfo, String repositoryId) { + logger.debug("START: fetchRepositoryData for repositoryId: {}", repositoryId); Map repoValueMap = new HashMap<>(); repoInfo = repoInfo.getJSONObject(repositoryId); JSONObject capabilities = repoInfo.getJSONObject("capabilities"); @@ -612,16 +649,22 @@ public Map fetchRepositoryData(JSONObject repoInfo, String re } } repoValueMap.put(repositoryId, repoValue); + logger.debug("END: fetchRepositoryData - VersionEnabled: {}, VirusScanEnabled: {}", + repoValue.getVersionEnabled(), repoValue.getVirusScanEnabled()); return repoValueMap; } @Override public int deleteDocument(String cmisaction, String objectId, String user) { + logger.info("Deleting document - action: {}, objectId: {}, user: {}", cmisaction, objectId, user); + long startTime = System.currentTimeMillis(); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); HttpClient httpClient; if (user.equals(SDMConstants.SYSTEM_USER)) { + logger.debug("Using TECHNICAL_USER_FLOW for deletion"); httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, TECHNICAL_USER_FLOW); } else { + logger.debug("Using authorities flow for deletion for user: {}", user); httpClient = tokenHandler.getHttpClientForAuthoritiesFlow(connectionPool, user); } @@ -634,8 +677,12 @@ public int deleteDocument(String cmisaction, String objectId, String user) { HttpEntity multipart = builder.build(); deleteDocumentRequest.setEntity(multipart); try (var response = (CloseableHttpResponse) httpClient.execute(deleteDocumentRequest)) { - return response.getStatusLine().getStatusCode(); + int statusCode = response.getStatusLine().getStatusCode(); + logger.info("Document deletion completed with status code: {} in {} ms", + statusCode, (System.currentTimeMillis() - startTime)); + return statusCode; } catch (IOException e) { + logger.error("Error deleting document {}: {}", objectId, e.getMessage(), e); throw new ServiceException( SDMErrorMessages.getGenericError(SDMUtils.getErrorMessage("EVENT_DELETE"))); } @@ -645,6 +692,7 @@ public int deleteDocument(String cmisaction, String objectId, String user) { public List getSecondaryTypes( String repositoryId, SDMCredentials sdmCredentials, boolean isSystemUser) throws ServiceException { + logger.debug("START: getSecondaryTypes for repositoryId: {}", repositoryId); SecondaryTypesKey secondaryTypesKey = new SecondaryTypesKey(); secondaryTypesKey.setRepositoryId(repositoryId); List secondaryTypes = new ArrayList<>(); @@ -677,11 +725,14 @@ public List getSecondaryTypes( } SDMUtils.extractSecondaryTypeIds(secondaryTypesJSON, result); } + logger.debug("END: getSecondaryTypes - found {} types", result.size()); return result; } catch (IOException e) { + logger.error("Error getting secondary types: {}", e.getMessage(), e); throw new ServiceException("Could not update the attachment", e); } } + logger.debug("END: getSecondaryTypes - returning from cache"); return secondaryTypes; } @@ -691,6 +742,7 @@ public List getValidSecondaryProperties( SDMCredentials sdmCredentials, String repositoryId, boolean isSystemUser) { + logger.debug("START: getValidSecondaryProperties for repositoryId: {}", repositoryId); SecondaryPropertiesKey secondaryPropertiesKey = new SecondaryPropertiesKey(); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; secondaryPropertiesKey.setRepositoryId(repositoryId); @@ -720,10 +772,12 @@ public List getValidSecondaryProperties( iterator.remove(); } } catch (IOException e) { + logger.error("Error getting type definition: {}", e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("UPDATE_ATTACHMENT_ERROR"), e); } } } + logger.debug("END: getValidSecondaryProperties - found {} valid properties", validSecondaryProperties.size()); return validSecondaryProperties; } @@ -735,6 +789,7 @@ public Map copyAttachment( boolean isSystemUser, Set customPropertiesInSDM) throws IOException { + logger.debug("START: copyAttachment for objectId: {}", cmisDocument.getObjectId()); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :{} flow", grantType); @@ -758,6 +813,7 @@ public Map copyAttachment( entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : ""; if (response.getStatusLine().getStatusCode() == 201) { + logger.debug("END: copyAttachment - copy successful"); return processCopyAttachmentResponse(responseBody, customPropertiesInSDM); } @@ -800,6 +856,7 @@ private String getRepositoryId(String jsonString) { @Override public JSONObject getChangeLog( String objectId, SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { + logger.debug("START: getChangeLog for objectId: {}", objectId); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("This is a :" + grantType + " flow"); var httpClient = tokenHandler.getHttpClient(binding, connectionPool, null, grantType); @@ -839,8 +896,10 @@ public JSONObject getChangeLog( } else if (responseCode != 200) { throw new ServiceException(SDMUtils.getErrorMessage("FETCH_CHANGELOG_ERROR")); } + logger.debug("END: getChangeLog - retrieved successfully"); return new JSONObject(responseString); } catch (IOException e) { + logger.error("Error fetching changelog for {}: {}", objectId, e.getMessage(), e); throw new ServiceException(SDMUtils.getErrorMessage("FETCH_CHANGELOG_ERROR"), e); } } @@ -885,6 +944,7 @@ private void extractCustomProperties( public String moveAttachment( CmisDocument cmisDocument, SDMCredentials sdmCredentials, boolean isSystemUser) throws IOException { + logger.debug("START: moveAttachment for objectId: {}", cmisDocument.getObjectId()); String grantType = isSystemUser ? TECHNICAL_USER_FLOW : NAMED_USER_FLOW; logger.info("Moving attachment - This is a :{} flow", grantType); 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 2f710096a..05ddd06dc 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 @@ -57,77 +57,119 @@ public SDMAttachmentsServiceHandler( @On(event = AttachmentService.EVENT_CREATE_ATTACHMENT) public void createAttachment(AttachmentCreateEventContext context) throws IOException { + long startTime = System.currentTimeMillis(); + String contentLength = (context.getParameterInfo() != null && context.getParameterInfo().getHeaders() != null) + ? context.getParameterInfo().getHeaders().get("content-length") + : null; logger.info( "CREATE_ATTACHMENT Event Received with content length {} At {}", - (context.getParameterInfo() != null && context.getParameterInfo().getHeaders() != null) - ? context.getParameterInfo().getHeaders().get("content-length") - : null, - System.currentTimeMillis()); + contentLength, + startTime); + logger.debug("User: {}, Tenant: {}", context.getUserInfo().getId(), context.getUserInfo().getTenant()); + validateRepository(context); + logger.debug("Repository validation completed"); + processEntities(context); + long endTime = System.currentTimeMillis(); + logger.info("CREATE_ATTACHMENT completed successfully in {} ms", (endTime - startTime)); } @On(event = AttachmentService.EVENT_MARK_ATTACHMENT_AS_DELETED) public void markAttachmentAsDeleted(AttachmentMarkAsDeletedEventContext context) throws IOException { + String contentId = context.getContentId(); + logger.debug("START: Mark attachment as deleted with contentId: {}", contentId); String[] contextValues = context.getContentId().split(":"); if (contextValues.length > 0 && !(contextValues[0].equalsIgnoreCase("null"))) { String objectId = contextValues[0]; String folderId = contextValues[1]; String entity = contextValues[2]; + logger.debug("Processing deletion - objectId: {}, folderId: {}, entity: {}", objectId, folderId, entity); + // check if only attachment exists against the folderId List cmisDocuments = dbQuery.getAttachmentsForFolder(entity, persistenceService, folderId, context); + logger.debug("Found {} attachments for folder: {}", cmisDocuments.size(), folderId); + if (cmisDocuments.isEmpty()) { // deleteFolder API + logger.info("Deleting folder: {} for entity: {}", folderId, entity); sdmService.deleteDocument("deleteTree", folderId, context.getDeletionUserInfo().getName()); + 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()); + logger.info("Document deleted successfully: {}", objectId); + } else { + logger.debug("ObjectId {} is still referenced, not deleting", objectId); } } + } else { + logger.warn("Invalid contentId format for deletion: {}", contentId); } context.setCompleted(); + logger.debug("END: Mark attachment as deleted"); } @On(event = AttachmentService.EVENT_RESTORE_ATTACHMENT) public void restoreAttachment(AttachmentRestoreEventContext context) { + logger.debug("Restore attachment event received - marking as completed"); context.setCompleted(); } @On(event = AttachmentService.EVENT_READ_ATTACHMENT) public void readAttachment(AttachmentReadEventContext context) throws IOException { + logger.debug("START: Read attachment"); + long startTime = System.currentTimeMillis(); String[] contentIdParts = context.getContentId().split(":"); String objectId = contentIdParts[0]; String entity = contentIdParts.length > 2 ? contentIdParts[2] : contentIdParts[0]; + logger.debug("Reading attachment - objectId: {}, entity: {}", objectId, entity); + SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); CmisDocument cmisDocument = dbQuery.getuploadStatusForAttachment(entity, persistenceService, objectId, context); + logger.debug("Attachment upload status: {}", cmisDocument.getUploadStatus()); + if (cmisDocument.getUploadStatus() != null && cmisDocument .getUploadStatus() - .equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_VIRUS_DETECTED)) + .equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_VIRUS_DETECTED)) { + logger.warn("Virus detected in attachment: {}", objectId); throw new ServiceException(SDMUtils.getErrorMessage("VIRUS_DETECTED_FILE_ERROR")); + } if (cmisDocument.getUploadStatus() != null - && cmisDocument.getUploadStatus().equalsIgnoreCase(SDMConstants.VIRUS_SCAN_INPROGRESS)) + && cmisDocument.getUploadStatus().equalsIgnoreCase(SDMConstants.VIRUS_SCAN_INPROGRESS)) { + logger.warn("Virus scan is in progress for attachment: {}", objectId); throw new ServiceException(SDMUtils.getErrorMessage("VIRUS_SCAN_IN_PROGRESS_FILE_ERROR")); + } if (cmisDocument.getUploadStatus() != null - && cmisDocument.getUploadStatus().equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) + && cmisDocument.getUploadStatus().equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) { + logger.warn("Upload is in progress for attachment: {}", objectId); throw new ServiceException(SDMUtils.getErrorMessage("UPLOAD_IN_PROGRESS_FILE_ERROR")); + } try { + logger.info("Initiating document read from repository for objectId: {}", objectId); sdmService.readDocument(objectId, sdmCredentials, context); + logger.info("Document read completed for objectId: {} in {} ms", objectId, (System.currentTimeMillis() - startTime)); } catch (Exception e) { + logger.error("Error reading document {} from repository: {}", objectId, e.getMessage(), e); throw new ServiceException(e.getMessage()); } context.setCompleted(); + logger.debug("END: Read attachment"); } public boolean duplicateCheck(String filename, String fileid, Result result) { + logger.debug("Checking for duplicate fileName: {} with ID: {}", filename, fileid); List> resultList = result.listOf(Map.class).stream() .map(map -> (Map) map) .collect(Collectors.toList()); + logger.debug("Checking against {} existing attachments", resultList.size()); Map duplicate = null; for (Map attachment : resultList) { @@ -143,60 +185,83 @@ public boolean duplicateCheck(String filename, String fileid, Result result) { } } - return duplicate != null; + boolean isDuplicate = duplicate != null; + logger.debug("Duplicate check result for {}: {}", filename, isDuplicate); + return isDuplicate; } private boolean isObjectIdPresent(List documents, String objectId) { + logger.debug("Checking if objectId {} exists in {} documents", objectId, documents.size()); for (CmisDocument doc : documents) { if (objectId.equals(doc.getObjectId())) { + logger.debug("ObjectId {} found in documents", objectId); return true; } } + logger.debug("ObjectId {} not found in documents", objectId); return false; } private void validateRepository(AttachmentCreateEventContext eventContext) throws ServiceException, IOException { + logger.debug("START: Validate repository"); String repositoryId = SDMConstants.REPOSITORY_ID; + logger.debug("Checking repository type for: {}", repositoryId); RepoValue repoValue = sdmService.checkRepositoryType(repositoryId, eventContext.getUserInfo().getTenant()); + if (repoValue.getVersionEnabled()) { + logger.warn("Repository is versioned which is not allowed: {}", repositoryId); throw new ServiceException(SDMUtils.getErrorMessage("VERSIONED_REPO_ERROR")); } + String len = eventContext.getParameterInfo().getHeaders().get("content-length"); long contentLen = !StringUtils.isEmpty(len) ? Long.parseLong(len) : -1; + logger.debug("Content length: {} bytes, Async virus scan enabled: {}, Virus scan enabled: {}", + contentLen, repoValue.getIsAsyncVirusScanEnabled(), repoValue.getVirusScanEnabled()); + // Check if repository is virus scanned if (!repoValue.getIsAsyncVirusScanEnabled() && repoValue.getVirusScanEnabled() && contentLen > 400 * 1024 * 1024 && !repoValue.getDisableVirusScannerForLargeFile()) { + logger.warn("File size exceeds 400MB and synchronous virus scan is enabled"); throw new ServiceException(SDMUtils.getErrorMessage("VIRUS_REPO_ERROR_MORE_THAN_400MB")); } + logger.debug("END: Repository validation successful"); } private void processEntities(AttachmentCreateEventContext eventContext) throws ServiceException, IOException { + logger.debug("START: Process entities for attachment creation"); Map attachmentIds = eventContext.getAttachmentIds(); CdsEntity attachmentDraftEntity = getAttachmentDraftEntity(eventContext); String upIdKey = SDMUtils.getUpIdKey(attachmentDraftEntity); String upID = (String) attachmentIds.get(upIdKey); + logger.debug("Processing attachments for upID: {} with key: {}", upID, upIdKey); Result result = dbQuery.getAttachmentsForUPID(attachmentDraftEntity, persistenceService, upID, upIdKey); checkAttachmentConstraints(eventContext, attachmentDraftEntity, upID, upIdKey); MediaData data = eventContext.getData(); + logger.debug("Attachment fileName: {}", data.getFileName()); validateFileName(data.getFileName(), result, attachmentIds); createDocumentInSDM(data, result, eventContext, attachmentIds, upIdKey, upID); + logger.debug("END: Process entities"); } private CdsEntity getAttachmentDraftEntity(AttachmentCreateEventContext eventContext) { CdsModel model = eventContext.getModel(); - Optional attachmentDraftEntity = - model.findEntity(eventContext.getAttachmentEntity() + "_drafts"); + String draftEntityName = eventContext.getAttachmentEntity() + "_drafts"; + logger.debug("Looking for attachment draft entity: {}", draftEntityName); + Optional attachmentDraftEntity = model.findEntity(draftEntityName); return attachmentDraftEntity.orElseThrow( - () -> new ServiceException(SDMUtils.getErrorMessage("DRAFT_NOT_FOUND"))); + () -> { + logger.error("Draft entity not found: {}", draftEntityName); + return new ServiceException(SDMUtils.getErrorMessage("DRAFT_NOT_FOUND")); + }); } private void checkAttachmentConstraints( @@ -205,6 +270,7 @@ private void checkAttachmentConstraints( String upID, String upIdKey) throws ServiceException { + logger.debug("START: Check attachment constraints for upID: {}", upID); // Fetch the row count for current repository Result result = dbQuery.getAttachmentsForUPIDAndRepository( @@ -213,25 +279,34 @@ private void checkAttachmentConstraints( Long maxCount = SDMUtils.getAttachmentCountAndMessage( eventContext.getModel().entities().toList(), eventContext.getAttachmentEntity()); + + logger.debug("Current attachment count: {}, Max allowed count: {}", rowCount, maxCount); if (maxCount > 0 && rowCount >= maxCount) { + logger.warn("Attachment count exceeds maximum limit: {} >= {}", rowCount, maxCount); throw new ServiceException( String.format(SDMUtils.getErrorMessage("MAX_COUNT_ERROR_MESSAGE"), maxCount.toString())); } + logger.debug("END: Attachment constraints validation passed"); } private void validateFileName(String filename, Result result, Map attachmentIds) throws ServiceException { + logger.debug("Validating fileName: {}", filename); if (filename == null || filename.isBlank()) { + logger.error("Invalid fileName: empty or null"); throw new ServiceException(SDMUtils.getErrorMessage("FILENAME_WHITESPACE_ERROR_MESSAGE")); } if (SDMUtils.hasRestrictedCharactersInName(filename)) { + logger.warn("FileName contains restricted characters: {}", filename); throw new ServiceException( SDMErrorMessages.nameConstraintMessage(Collections.singletonList(filename))); } String fileid = (String) attachmentIds.get("ID"); if (duplicateCheck(filename, fileid, result)) { + logger.warn("Duplicate fileName detected: {}", filename); throw new ServiceException(SDMErrorMessages.getDuplicateFilesError(filename)); } + logger.debug("fileName validation passed"); } private void createDocumentInSDM( @@ -242,33 +317,41 @@ private void createDocumentInSDM( String upIdKey, String upID) throws ServiceException, IOException { + logger.debug("START: Create document in SDM for attachment"); + long startTime = System.currentTimeMillis(); CmisDocument cmisDocument = new CmisDocument(); Boolean isSystemUser = eventContext.getUserInfo().isSystemUser(); String repositoryId = SDMConstants.REPOSITORY_ID; String entityName = eventContext.getAttachmentEntity().getQualifiedName().split("\\.")[2]; String folderName = upID + "__" + entityName; + logger.debug("Creating folder structure - folderName: {}, isSystemUser: {}", folderName, isSystemUser); + String folderId = sdmService.getFolderId(result, persistenceService, folderName, isSystemUser); + logger.debug("Obtained folderId: {} for folder: {}", folderId, folderName); + String len = eventContext.getParameterInfo().getHeaders().get("content-length"); long contentLen = !StringUtils.isEmpty(len) ? Long.parseLong(len) : -1; setCmisDocumentProperties( cmisDocument, data, attachmentIds, folderId, repositoryId, upIdKey, contentLen); + logger.debug("CMIS document properties set - fileName: {}, contentLength: {}", data.getFileName(), contentLen); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); JSONObject createResult = null; try { + logger.info("Initiating document creation in SDM repository"); createResult = documentService.createDocument(cmisDocument, sdmCredentials, isSystemUser, eventContext); - logger.info("Synchronous Response from documentService: {}", createResult); - logger.info("Upload Finished at: {}", System.currentTimeMillis()); + logger.debug("Document creation response received: {}", createResult != null ? createResult.toString() : "null"); } catch (Exception e) { - logger.error("Error in documentService: \n{}", Arrays.toString(e.getStackTrace())); + logger.error("Error creating document in SDM service: {}", e.getMessage(), e); throw new ServiceException( SDMErrorMessages.getGenericError(AttachmentService.EVENT_CREATE_ATTACHMENT), e); } - logger.info("Synchronous Response from documentService: {}", createResult); - logger.info("Upload Finished at: {}", System.currentTimeMillis()); + + logger.info("Upload Finished at: {} (duration: {} ms)", System.currentTimeMillis(), (System.currentTimeMillis() - startTime)); handleCreateDocumentResult(cmisDocument, createResult, eventContext); + logger.debug("END: Create document in SDM"); } private void setCmisDocumentProperties( @@ -293,9 +376,11 @@ private void handleCreateDocumentResult( CmisDocument cmisDocument, JSONObject createResult, AttachmentCreateEventContext eventContext) throws ServiceException { String status = createResult.get("status").toString(); + logger.debug("Document creation result status: {}", status); switch (status) { case "duplicate": + logger.warn("Duplicate document detected: {}", cmisDocument.getFileName()); Object[] duplicatemessage = new Object[1]; duplicatemessage[0] = cmisDocument.getFileName(); throw new ServiceException( @@ -303,15 +388,19 @@ private void handleCreateDocumentResult( SDMUtils.getErrorMessage("SINGLE_DUPLICATE_FILENAME"), duplicatemessage[0].toString())); case "virus": + logger.error("Virus detected in document: {}", cmisDocument.getFileName()); Object[] message = new Object[1]; message[0] = cmisDocument.getFileName(); throw new ServiceException(SDMErrorMessages.getVirusFilesError(message[0].toString())); case "fail": + logger.error("Document creation failed: {}", createResult.get("message")); throw new ServiceException(createResult.get("message").toString()); case "unauthorized": + logger.error("User not authorized to upload document"); throw new ServiceException(SDMUtils.getErrorMessage("USER_NOT_AUTHORISED_ERROR")); case "blocked": + logger.warn("Document MIME type is blocked: {}", cmisDocument.getMimeType()); throw new ServiceException(SDMUtils.getErrorMessage("MIMETYPE_INVALID_ERROR")); default: cmisDocument.setObjectId(createResult.get("objectId").toString()); @@ -319,6 +408,8 @@ private void handleCreateDocumentResult( (createResult.get("uploadStatus") != null) ? createResult.get("uploadStatus").toString() : SDMConstants.UPLOAD_STATUS_IN_PROGRESS); + logger.info("Document created successfully with objectId: {} and status: {}", + cmisDocument.getObjectId(), cmisDocument.getUploadStatus()); dbQuery.addAttachmentToDraft( getAttachmentDraftEntity(eventContext), persistenceService, cmisDocument); finalizeContext(eventContext, cmisDocument); @@ -327,6 +418,7 @@ private void handleCreateDocumentResult( private void finalizeContext( AttachmentCreateEventContext eventContext, CmisDocument cmisDocument) { + logger.debug("Finalizing attachment context for objectId: {}", cmisDocument.getObjectId()); eventContext.setContentId( cmisDocument.getObjectId() + ":" @@ -336,5 +428,6 @@ private void finalizeContext( eventContext.getData().setStatus("Clean"); eventContext.getData().setContent(null); eventContext.setCompleted(); + logger.debug("Attachment context finalized and marked as completed"); } } 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 74698bdee..9b15982ea 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 @@ -84,8 +84,13 @@ public SDMCustomServiceHandler( @On(event = RegisterService.EVENT_COPY_ATTACHMENT) public void copyAttachments(AttachmentCopyEventContext context) throws IOException { + logger.debug("START: Copy attachments event"); String parentEntity = context.getParentEntity(); String compositionName = context.getCompositionName(); + logger.debug( + "Copy attachments request - parentEntity: {}, compositionName: {}", + parentEntity, + compositionName); Optional entity = context.getModel().findEntity(parentEntity + "." + compositionName); @@ -165,7 +170,12 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti CdsEntity targetEntity = entity.isPresent() ? entity.get() : null; createDraftEntries(draftRequest, customPropertyDefinitions, targetEntity); + logger.info( + "Copy attachments completed - {} attachments copied for upID: {}", + attachmentsMetadata.size(), + upID); context.setCompleted(); + logger.debug("END: Copy attachments event"); } /** @@ -178,6 +188,7 @@ public void copyAttachments(AttachmentCopyEventContext context) throws IOExcepti */ @On(event = RegisterService.EVENT_MOVE_ATTACHMENT) public void moveAttachments(AttachmentMoveEventContext context) throws IOException { + logger.debug("START: Move attachments event"); String parentEntity = context.getParentEntity(); String compositionName = context.getCompositionName(); String upID = context.getUpId(); @@ -186,6 +197,14 @@ public void moveAttachments(AttachmentMoveEventContext context) throws IOExcepti String repositoryId = SDMConstants.REPOSITORY_ID; Boolean isSystemUser = context.getSystemUser(); List objectIds = context.getObjectIds(); + logger.debug( + "Move request - parentEntity: {}, compositionName: {}, upID: {}, sourceFolderId: {}," + + " objectIds count: {}", + parentEntity, + compositionName, + upID, + sourceFolderId, + objectIds.size()); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); @@ -276,6 +295,7 @@ public void moveAttachments(AttachmentMoveEventContext context) throws IOExcepti } } + logger.debug("END: Move attachments event"); context.setCompleted(); } @@ -527,25 +547,32 @@ private TargetFolderInfo ensureTargetFolderReady( private String ensureFolderExists( String folderName, String repositoryId, SDMCredentials sdmCredentials, Boolean isSystemUser) throws IOException { + logger.debug("Ensuring folder exists: {}", folderName); String folderId = sdmService.getFolderIdByPath(folderName, repositoryId, sdmCredentials, isSystemUser); if (folderId == null) { + logger.debug("Folder {} not found, creating new folder", folderName); folderId = sdmService.createFolder( folderName, SDMConstants.REPOSITORY_ID, sdmCredentials, isSystemUser); JSONObject jsonObject = new JSONObject(folderId); JSONObject succinctProperties = jsonObject.getJSONObject("succinctProperties"); folderId = succinctProperties.getString("cmis:objectId"); + logger.debug("Created folder {} with folderId: {}", folderName, folderId); + } else { + logger.debug("Folder {} already exists with folderId: {}", folderName, folderId); } return folderId; } private CopyAttachmentsResult copyAttachmentsToSDM( CopyAttachmentsRequest request, Set customPropertiesInSDM) throws IOException { + logger.debug("START: Copy {} attachments to SDM", request.getObjectIds().size()); List> attachmentsMetadata = new ArrayList<>(); List populatedDocuments = new ArrayList<>(); for (String objectId : request.getObjectIds()) { + logger.debug("Processing copy for objectId: {}", objectId); CmisDocument cmisDocument = dbQuery.getAttachmentForObjectID(persistenceService, objectId, request.getContext()); cmisDocument.setObjectId(objectId); @@ -568,7 +595,9 @@ private CopyAttachmentsResult copyAttachmentsToSDM( customPropertiesInSDM); attachmentsMetadata.add(attachmentData); + logger.debug("Successfully copied attachment: {}", objectId); } catch (ServiceException e) { + logger.error("Failed to copy attachment {}: {}", objectId, e.getMessage()); handleCopyFailure( request.getContext(), request.getFolderId(), @@ -578,6 +607,7 @@ private CopyAttachmentsResult copyAttachmentsToSDM( } } + logger.debug("END: Copy attachments to SDM - {} successful", attachmentsMetadata.size()); return new CopyAttachmentsResult(attachmentsMetadata, populatedDocuments); } @@ -1492,9 +1522,12 @@ private void handleCopyFailure( List> attachmentsMetadata, ServiceException e) throws IOException { + 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()); } 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()); @@ -1504,15 +1537,21 @@ private void handleCopyFailure( } private String resolveUpIdKey(EventContext context, String parentEntity, String compositionName) { + logger.debug( + "Resolving upIdKey for parentEntity: {}, compositionName: {}", + parentEntity, + compositionName); CdsModel model = context.getModel(); Optional optionalParentEntity = model.findEntity(parentEntity); if (optionalParentEntity.isEmpty()) { + logger.error("Parent entity not found: {}", parentEntity); throw new ServiceException("Unable to find parent entity: " + parentEntity); } Optional compositionElement = optionalParentEntity.get().findElement(compositionName); if (compositionElement.isEmpty() || !compositionElement.get().getType().isAssociation()) { + logger.error("Composition '{}' not found in entity: {}", compositionName, parentEntity); throw new ServiceException( "Unable to find composition '" + compositionName + "' in entity: " + parentEntity); } @@ -1528,9 +1567,11 @@ private String resolveUpIdKey(EventContext context, String parentEntity, String CdsAssociationType upAssocType = association.getType(); List fkElements = upAssocType.refs().map(ref -> "up__" + ref.path()).toList(); String upIdKey = fkElements.get(0); + logger.debug("Resolved upIdKey: {}", upIdKey); return upIdKey; } } + logger.warn("Could not resolve upIdKey for parentEntity: {}", parentEntity); return null; } @@ -1542,6 +1583,9 @@ private String resolveUpIdKey(EventContext context, String parentEntity, String * @param data encapsulated draft entry creation data */ private void createDraftEntriesForMove(DraftEntryMoveData data) { + logger.debug( + "Creating {} draft entries for moved attachments", + data.getMovedAttachmentsMetadata().size()); for (int i = 0; i < data.getMovedAttachmentsMetadata().size(); i++) { List attachmentMetadata = data.getMovedAttachmentsMetadata().get(i); CmisDocument cmisDocument = data.getPopulatedDocuments().get(i); @@ -1551,6 +1595,7 @@ private void createDraftEntriesForMove(DraftEntryMoveData data) { performDraftInsertWithRetry(updatedFields, data); } + logger.debug("Completed creating draft entries for moved attachments"); } /** @@ -1742,6 +1787,9 @@ private void createDraftEntries( CreateDraftEntriesRequest request, Map customPropertyDefinitions, CdsEntity targetEntity) { + logger.debug( + "Creating {} draft entries for copied attachments", + request.getAttachmentsMetadata().size()); for (int i = 0; i < request.getAttachmentsMetadata().size(); i++) { Map attachmentMetadata = request.getAttachmentsMetadata().get(i); @@ -1752,6 +1800,7 @@ private void createDraftEntries( String mimeType = attachmentMetadata.get("cmis:contentStreamMimeType"); String description = attachmentMetadata.get("cmis:description"); String newObjectId = attachmentMetadata.get("cmis:objectId"); + logger.debug("Processing draft entry for objectId: {}, fileName: {}", newObjectId, fileName); updatedFields.put(OBJECT_ID_KEY, newObjectId); updatedFields.put("repositoryId", request.getRepositoryId()); @@ -1823,10 +1872,12 @@ private void createDraftEntries( "Failed to insert attachment entry in DB after retries: " + e.getMessage(), e); } } else { + logger.error("No suitable service found for entity: {}", request.getParentEntity()); throw new ServiceException( "No suitable service found for entity: " + request.getParentEntity()); } } + logger.debug("Completed creating draft entries for copied attachments"); } /** 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 28cd25403..9819454ef 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,6 +72,7 @@ public SDMServiceGenericHandler( @On(event = "changelog") public void changelog(AttachmentLogContext context) throws IOException { + logger.debug("START: Changelog event"); CdsModel cdsModel = context.getModel(); CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel); @@ -84,12 +85,14 @@ public void changelog(AttachmentLogContext context) throws IOException { // get the objectId against the Id String id = targetKeys.get("ID").toString(); + logger.debug("Fetching changelog for attachment ID: {}", id); CmisDocument cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); if (cmisDocument.getFileName() == null || cmisDocument.getFileName().isEmpty()) { // open attachment is triggered on non-draft entity + logger.debug("Draft entity returned empty fileName, fetching from active entity"); attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName()); cmisDocument = @@ -103,15 +106,19 @@ public void changelog(AttachmentLogContext context) throws IOException { cmisDocument.getObjectId(), sdmCredentials, context.getUserInfo().isSystemUser()); jsonObject.put("filename", cmisDocument.getFileName()); + logger.info("Changelog fetched for objectId: {}", cmisDocument.getObjectId()); context.setResult(jsonObject); + logger.debug("END: Changelog event"); } @On(event = "copyAttachments") public void copyAttachments(EventContext context) throws IOException { + logger.debug("START: Copy attachments event"); String upID = context.get("up__ID").toString(); String objectIdsString = context.get("objectIds").toString(); List objectIds = Arrays.stream(objectIdsString.split(",")).map(String::trim).toList(); + logger.debug("Copy request - upID: {}, objectIds count: {}", upID, objectIds.size()); // Use the full target qualified name as the facet String facet = context.getTarget().getQualifiedName(); @@ -119,11 +126,14 @@ public void copyAttachments(EventContext context) throws IOException { var copyEventInput = new CopyAttachmentInput(upID, facet, objectIds); attachmentService.copyAttachments(copyEventInput, context.getUserInfo().isSystemUser()); + logger.info("Copy attachments completed for upID: {}", upID); context.setCompleted(); + logger.debug("END: Copy attachments event"); } @On(event = "moveAttachments") public void moveAttachments(AttachmentMoveRequestContext context) throws IOException { + logger.debug("START: Move attachments event"); String upID = context.get("up__ID").toString(); String sourceFolderId = context.get("sourceFolderId").toString(); String objectIdsString = context.get("objectIds").toString(); @@ -131,6 +141,12 @@ public void moveAttachments(AttachmentMoveRequestContext context) throws IOExcep String sourceFacet = context.get("sourceFacet") != null ? context.get("sourceFacet").toString() : null; String targetFacet = context.get("targetFacet").toString(); + logger.debug( + "Move request - upID: {}, sourceFolderId: {}, targetFacet: {}, objectIds count: {}", + upID, + sourceFolderId, + targetFacet, + objectIds.size()); var moveEventInput = new MoveAttachmentInput(sourceFolderId, upID, targetFacet, objectIds, sourceFacet); @@ -141,26 +157,32 @@ public void moveAttachments(AttachmentMoveRequestContext context) throws IOExcep context.setResult(result); context.setCompleted(); + logger.debug("END: Move attachments event"); } @On(event = "createLink") public void create(EventContext context) throws IOException { + logger.debug("START: Create link event"); validateRepository(context); createLink(context); + logger.debug("END: Create link event"); } @On(event = "editLink") public void edit(EventContext context) throws IOException { - logger.info("Handling event " + context.getEvent()); + logger.debug("START: Edit link event for {}", context.getEvent()); editLink(context); + logger.debug("END: Edit link event"); } @Before(event = DraftService.EVENT_DRAFT_CANCEL) public void handleDraftDiscardForLinks(DraftCancelEventContext context) throws IOException { + logger.debug("START: Handle draft discard for links"); CdsEntity parentDraftEntity = context.getTarget(); CqnAnalyzer analyzer = CqnAnalyzer.create(context.getModel()); Map parentKeys = analyzer.analyze(context.getCqn()).rootKeys(); String parentEntityName = parentDraftEntity.getQualifiedName().replace("_drafts", ""); + logger.debug("Processing draft cancel for entity: {}", parentEntityName); Optional parentActiveEntityOpt = context.getModel().findEntity(parentEntityName); Map compositionPathMapping = @@ -171,14 +193,17 @@ public void handleDraftDiscardForLinks(DraftCancelEventContext context) throws I context.getModel(), cdsEntity, persistenceService)) .orElse(new HashMap<>()); + logger.debug("Found {} composition paths to process", compositionPathMapping.size()); for (Map.Entry entry : compositionPathMapping.entrySet()) { String attachmentCompositionDefinition = entry.getKey(); revertLinksForComposition(context, parentKeys, attachmentCompositionDefinition); } revertNestedEntityLinks(context); + logger.debug("END: Handle draft discard for links"); } private void revertNestedEntityLinks(DraftCancelEventContext context) throws IOException { + logger.debug("START: Revert nested entity links"); CdsEntity parentDraftEntity = context.getTarget(); String parentEntityName = parentDraftEntity.getQualifiedName().replace("_drafts", ""); @@ -198,10 +223,12 @@ private void revertNestedEntityLinks(DraftCancelEventContext context) throws IOE } }); } + logger.debug("END: Revert nested entity links"); } private void processNestedEntityComposition( DraftCancelEventContext context, CdsElement composition) throws IOException { + logger.debug("Processing nested entity composition: {}", composition.getName()); CdsAssociationType associationType = (CdsAssociationType) composition.getType(); String targetEntityName = associationType.getTarget().getQualifiedName(); @@ -215,6 +242,7 @@ private void processNestedEntityComposition( context.getModel(), associationType.getTarget(), persistenceService); if (nestedAttachmentMapping.isEmpty()) { + logger.debug("No attachment mapping found for nested entity: {}", targetEntityName); return; } @@ -224,6 +252,7 @@ private void processNestedEntityComposition( Result nestedRecords = persistenceService.run( Select.from(nestedDraftEntity.get()).where(e -> e.get("IsActiveEntity").eq(false))); + logger.debug("Found {} nested records to process", nestedRecords.rowCount()); for (Row nestedRecord : nestedRecords) { Map nestedEntityKeys = new HashMap<>(); @@ -247,6 +276,7 @@ private void revertLinksForComposition( Map parentKeys, String attachmentCompositionDefinition) throws IOException { + logger.debug("Reverting links for composition: {}", attachmentCompositionDefinition); CdsModel model = context.getModel(); String draftEntityName = attachmentCompositionDefinition + "_drafts"; @@ -255,6 +285,7 @@ private void revertLinksForComposition( final String upIdKey = SDMUtils.getUpIdKey(draftEntity); if (upIdKey == null || upIdKey.isEmpty()) { + logger.debug("No upIdKey found, skipping revert for: {}", attachmentCompositionDefinition); return; } String parentKeyName = upIdKey.replaceFirst("^up__", ""); @@ -270,6 +301,7 @@ private void revertLinksForComposition( .and(a.get("IsActiveEntity").eq(false))); Result draftLinks = persistenceService.run(selectDraftLinks); + logger.debug("Found {} draft links to process", draftLinks.rowCount()); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); Boolean isSystemUser = context.getUserInfo().isSystemUser(); @@ -288,6 +320,7 @@ private void revertLinksForComposition( getOriginalUrlFromActiveTable(activeEntity, attachmentId, parentId, upIdKey); if (originalUrl != null && !originalUrl.equals(draftLinkUrl)) { + logger.debug("Reverting link {} from {} to {}", objectId, draftLinkUrl, originalUrl); revertLinkInSDM(objectId, filename, originalUrl, sdmCredentials, isSystemUser); } } @@ -295,6 +328,7 @@ private void revertLinksForComposition( private String getOriginalUrlFromActiveTable( CdsEntity activeEntity, String attachmentId, Object parentId, String upIdKey) { + logger.debug("Fetching original URL for attachment: {}", attachmentId); CqnSelect selectActiveLink = Select.from(activeEntity) .columns("linkUrl") @@ -312,8 +346,10 @@ private String getOriginalUrlFromActiveTable( Row activeRow = activeResult.single(); String originalUrl = activeRow.get("linkUrl") != null ? activeRow.get("linkUrl").toString() : null; + logger.debug("Found original URL: {}", originalUrl); return originalUrl; } else { + logger.debug("No original URL found for attachment: {}", attachmentId); return null; } } @@ -325,6 +361,7 @@ private void revertLinkInSDM( SDMCredentials sdmCredentials, Boolean isSystemUser) throws IOException { + logger.debug("Reverting link in SDM - objectId: {}, filename: {}", objectId, filename); CmisDocument cmisDocToRevert = new CmisDocument(); cmisDocToRevert.setObjectId(objectId); @@ -333,10 +370,12 @@ private void revertLinkInSDM( cmisDocToRevert.setUrl(originalUrl); cmisDocToRevert.setRepositoryId(SDMConstants.REPOSITORY_ID); sdmService.editLink(cmisDocToRevert, sdmCredentials, isSystemUser); + logger.debug("Link reverted successfully in SDM for objectId: {}", objectId); } @On(event = "openAttachment") public void openAttachment(AttachmentReadContext context) throws Exception { + logger.debug("START: Open attachment event"); CdsModel cdsModel = context.getModel(); CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel); Optional attachmentEntity = @@ -345,6 +384,7 @@ public void openAttachment(AttachmentReadContext context) throws Exception { cqnAnalyzer.analyze((CqnSelect) context.get("cqn")).targetKeyValues(); // get the objectId against the Id String id = targetKeys.get("ID").toString(); + logger.debug("Opening attachment with ID: {}", id); CmisDocument cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentEntity.get(), persistenceService, id); if (cmisDocument.getUploadStatus() != null @@ -375,31 +415,40 @@ public void openAttachment(AttachmentReadContext context) throws Exception { cmisDocument.getObjectId(), sdmCredentials, context.getUserInfo().isSystemUser()); if (objectResponse == null) { + logger.warn("File not found in SDM for objectId: {}", cmisDocument.getObjectId()); throw new ServiceException(SDMConstants.FILE_NOT_FOUND_ERROR); } } catch (ServiceException e) { if (e.getMessage() != null && e.getMessage().contains("User does not have required scope")) { + logger.warn("User not authorized to open link: {}", cmisDocument.getObjectId()); throw new ServiceException(SDMConstants.USER_NOT_AUTHORISED_ERROR_OPEN_LINK); } throw e; } + logger.info("Opening link attachment: {}", cmisDocument.getFileName()); context.setResult(cmisDocument.getUrl()); } else { + logger.debug("Attachment is not a link, returning None"); context.setResult("None"); } + logger.debug("END: Open attachment event"); } private void validateRepository(EventContext eventContext) throws ServiceException, IOException { + logger.debug("Validating repository"); String repositoryId = SDMConstants.REPOSITORY_ID; RepoValue repoValue = sdmService.checkRepositoryType(repositoryId, eventContext.getUserInfo().getTenant()); if (repoValue.getVersionEnabled()) { + logger.warn("Repository is versioned which is not allowed: {}", repositoryId); throw new ServiceException(SDMUtils.getErrorMessage("VERSIONED_REPO_ERROR")); } + logger.debug("Repository validation successful"); } private void createLink(EventContext context) throws IOException { + logger.debug("START: Create link"); String repositoryId = SDMConstants.REPOSITORY_ID; CdsModel cdsModel = context.getModel(); @@ -451,6 +500,7 @@ private void createLink(EventContext context) throws IOException { cmisDocument.setMimeType(SDMConstants.MIMETYPE_INTERNET_SHORTCUT); cmisDocument.setRepositoryId(repositoryId); cmisDocument.setUrl(context.get("url").toString()); + logger.debug("Creating link - fileName: {}, folderId: {}", filenameInRequest, folderId); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); JSONObject createResult = null; @@ -459,12 +509,15 @@ private void createLink(EventContext context) throws IOException { createResult = documentService.createDocument(cmisDocument, sdmCredentials, isSystemUser, null); } catch (Exception e) { + logger.error("Failed to create link: {}", e.getMessage()); throw new ServiceException(SDMUtils.getErrorMessage("ENTITY_PROCESSING_ERROR_LINK"), e); } handleCreateLinkResult(cmisDocument, createResult, context, upID, upIdKey); + logger.debug("END: Create link"); } private void editLink(EventContext context) throws IOException { + logger.debug("START: Edit link"); CdsModel cdsModel = context.getModel(); CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel); Optional attachmentDraftEntity = @@ -472,6 +525,7 @@ private void editLink(EventContext context) throws IOException { Map targetKeys = cqnAnalyzer.analyze((CqnSelect) context.get("cqn")).targetKeyValues(); String ID = targetKeys.get("ID").toString(); + logger.debug("Editing link with ID: {}", ID); CmisDocument cmisDocument = dbQuery.getObjectIdForAttachmentID(attachmentDraftEntity.get(), persistenceService, ID); cmisDocument.setUrl(context.get("url").toString()); @@ -488,15 +542,18 @@ private void editLink(EventContext context) throws IOException { .data(updatedFields) .where(doc -> doc.get("ID").eq(ID)); persistenceService.run(update); - logger.info("Successfully edited link"); + logger.info("Successfully edited link for ID: {}", ID); } else { if (status.equals("unauthorized")) { + logger.warn("User not authorized to edit link"); throw new ServiceException(SDMUtils.getErrorMessage("SDM_MISSING_ROLES_EXCEPTION")); } else { + logger.error("Failed to edit link - status: {}", status); throw new ServiceException(SDMUtils.getErrorMessage("FAILED_TO_EDIT_LINK")); } } context.setCompleted(); + logger.debug("END: Edit link"); } /** @@ -514,6 +571,7 @@ private List getKeyElementNames(CdsEntity entity) { private void checkAttachmentConstraints( EventContext context, CdsEntity attachmentDraftEntity, String upID, String upIdKey) throws ServiceException { + logger.debug("Checking attachment constraints for upID: {}", upID); CdsModel cdsModel = context.getModel(); CdsEntity attachmentEntity = cdsModel.findEntity(context.getTarget().getQualifiedName()).get(); @@ -525,33 +583,44 @@ private void checkAttachmentConstraints( Long maxCount = SDMUtils.getAttachmentCountAndMessage( context.getModel().entities().toList(), attachmentEntity); + logger.debug("Current count: {}, Max allowed: {}", rowCount, maxCount); if (maxCount > 0 && rowCount >= maxCount) { + logger.warn("Attachment count {} exceeds max allowed {}", rowCount, maxCount); throw new ServiceException( String.format(SDMUtils.getErrorMessage("MAX_COUNT_ERROR_MESSAGE"), maxCount.toString())); } } private void validateLinkName(String filename, Result result) throws ServiceException { + logger.debug("Validating link name: {}", filename); if (filename == null || filename.isBlank()) { + logger.error("Link name is blank or null"); throw new ServiceException(SDMUtils.getErrorMessage("FILENAME_WHITESPACE_ERROR_MESSAGE")); } if (SDMUtils.hasRestrictedCharactersInName(filename)) { + logger.warn("Link name contains restricted characters: {}", filename); throw new ServiceException( SDMErrorMessages.nameConstraintMessage(Collections.singletonList(filename))); } if (duplicateCheck(filename, result)) { + logger.warn("Duplicate link name detected: {}", filename); throw new ServiceException(SDMErrorMessages.getDuplicateFilesError(filename)); } + logger.debug("Link name validation passed"); } public boolean duplicateCheck(String filenameToCheck, Result result) { + logger.debug("Checking for duplicate: {}", filenameToCheck); List> resultList = result.listOf(Map.class).stream().map(m -> (Map) m).toList(); - return resultList.stream() - .anyMatch( - attachment -> - filenameToCheck.equals(attachment.get("fileName")) - && SDMConstants.REPOSITORY_ID.equals(attachment.get("repositoryId"))); + boolean isDuplicate = + resultList.stream() + .anyMatch( + attachment -> + filenameToCheck.equals(attachment.get("fileName")) + && SDMConstants.REPOSITORY_ID.equals(attachment.get("repositoryId"))); + logger.debug("Duplicate check result for {}: {}", filenameToCheck, isDuplicate); + return isDuplicate; } private void handleCreateLinkResult( @@ -561,20 +630,29 @@ private void handleCreateLinkResult( String upID, String upIdKey) throws ServiceException { + logger.debug("Handling create link result"); String repositoryId = SDMConstants.REPOSITORY_ID; String status = createResult.get("status").toString(); + logger.debug("Create link result status: {}", status); switch (status) { case "duplicate": + logger.warn("Duplicate link detected: {}", cmisDocument.getFileName()); throw new ServiceException( SDMErrorMessages.getDuplicateFilesError(cmisDocument.getFileName())); case "fail": + logger.error("Link creation failed: {}", createResult.get("message")); throw new ServiceException(createResult.get("message").toString()); case "unauthorized": + logger.warn("User not authorized to create link"); throw new ServiceException(SDMUtils.getErrorMessage("USER_NOT_AUTHORISED_ERROR_LINK")); default: cmisDocument.setObjectId(createResult.get("objectId").toString()); cmisDocument.setParentId(upID); + logger.info( + "Link created successfully - objectId: {}, fileName: {}", + cmisDocument.getObjectId(), + cmisDocument.getFileName()); Map updatedFields = new HashMap<>(); updatedFields.put("objectId", cmisDocument.getObjectId()); @@ -604,8 +682,9 @@ private void handleCreateLinkResult( draftS.newDraft(insert); } } + logger.debug("Link draft entry created successfully"); } catch (Exception e) { - logger.info("Exception in insert : " + e.getMessage()); + logger.error("Exception in insert: {}", e.getMessage(), e); } context.setCompleted(); } diff --git a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java index a40cb355c..91a9c4bdf 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java +++ b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java @@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory; public class SDMUtils { - private static final Logger logger = LoggerFactory.getLogger(CacheConfig.class); + private static final Logger logger = LoggerFactory.getLogger(SDMUtils.class); private SDMUtils() { // Doesn't do anything @@ -49,6 +49,7 @@ private SDMUtils() { public static Set FileNameContainsWhitespace( List data, String composition, String targetEntity) { + logger.debug("START: FileNameContainsWhitespace for composition: {}", composition); Set filenamesWithWhitespace = new HashSet<>(); for (Map entity : data) { List> attachments = @@ -64,11 +65,13 @@ public static Set FileNameContainsWhitespace( } } } + logger.debug("END: FileNameContainsWhitespace - found {} issues", filenamesWithWhitespace.size()); return filenamesWithWhitespace; } public static Set FileNameDuplicateInDrafts( List data, String composition, String targetEntity, String upIdKey) { + logger.debug("START: FileNameDuplicateInDrafts for composition: {}", composition); Set uniqueFilenames = new HashSet<>(); Set duplicateFilenames = new HashSet<>(); for (Map entity : data) { @@ -92,11 +95,13 @@ public static Set FileNameDuplicateInDrafts( } } } + logger.debug("END: FileNameDuplicateInDrafts - found {} duplicates", duplicateFilenames.size()); return duplicateFilenames; } public static List FileNameContainsRestrictedCharaters( List data, String composition, String targetEntity) { + logger.debug("START: FileNameContainsRestrictedCharaters for composition: {}", composition); List restrictedFilenames = new ArrayList<>(); for (Map entity : data) { List> attachments = @@ -112,6 +117,7 @@ public static List FileNameContainsRestrictedCharaters( } } } + logger.debug("END: FileNameContainsRestrictedCharaters - found {} restricted", restrictedFilenames.size()); return restrictedFilenames; } @@ -150,6 +156,7 @@ public static void prepareSecondaryProperties( public static Boolean checkMCM(HttpEntity responseEntity, List secondaryPropertyIds) throws IOException { + logger.debug("START: checkMCM"); Boolean flag = false; String responseString = EntityUtils.toString(responseEntity, "UTF-8"); @@ -180,6 +187,7 @@ public static Boolean checkMCM(HttpEntity responseEntity, List secondary flag = true; } } + logger.debug("END: checkMCM - found MCM properties: {}", flag); return flag; } @@ -424,6 +432,7 @@ public static Map getUpdatedSecondaryProperties( public static Long getAttachmentCountAndMessage( List entities, CdsEntity attachmentEntity) { + logger.debug("START: getAttachmentCountAndMessage for entity: {}", attachmentEntity.getQualifiedName()); Long maxCount = CacheConfig.getMaxAllowedAttachmentsCache().get(attachmentEntity.getQualifiedName()); @@ -434,6 +443,7 @@ public static Long getAttachmentCountAndMessage( CacheConfig.getMaxAllowedAttachmentsCache() .put(attachmentEntity.getQualifiedName(), maxCount); } + logger.debug("END: getAttachmentCountAndMessage - maxCount: {}", maxCount); return maxCount; } @@ -454,6 +464,7 @@ public static boolean isRelatedEntity(CdsEntity attachmentEntity, CdsEntity cdsE } public static String getUpIdKey(CdsEntity attachmentDraftEntity) { + logger.debug("START: getUpIdKey for entity: {}", attachmentDraftEntity.getQualifiedName()); String upIdKey = ""; Optional upAssociation = attachmentDraftEntity.findAssociation("up_"); if (upAssociation.isPresent()) { @@ -474,6 +485,7 @@ public static String getUpIdKey(CdsEntity attachmentDraftEntity) { upIdKey = upElement.get().getName(); } } + logger.debug("END: getUpIdKey - key: {}", upIdKey); return upIdKey; } @@ -510,6 +522,7 @@ private static List getKeyElementNames(CdsEntity entity) { * @throws com.sap.cds.services.ServiceException if UP ID cannot be extracted */ public static String fetchUPIDFromCQN(CqnSelect select, CdsEntity parentEntity) { + logger.debug("START: fetchUPIDFromCQN"); try { String upID = null; ObjectMapper mapper = new ObjectMapper(); @@ -547,6 +560,7 @@ public static String fetchUPIDFromCQN(CqnSelect select, CdsEntity parentEntity) } } // Return null if UP ID is not found (valid scenario) + logger.debug("END: fetchUPIDFromCQN - upID: {}", upID); return upID; } catch (Exception e) { logger.error(SDMConstants.ENTITY_PROCESSING_ERROR_LINK, e); From 3ce44c22ba5c993a3e390a7a37e7e94264542704 Mon Sep 17 00:00:00 2001 From: deepikaSingh2711 Date: Mon, 23 Feb 2026 15:31:58 +0530 Subject: [PATCH 2/2] Spotless Indentation Changes --- .../helper/AttachmentsHandlerUtils.java | 58 ++++++++++--- .../handler/common/SDMAttachmentsReader.java | 5 +- .../sdm/service/DocumentUploadService.java | 49 +++++++---- .../cds/sdm/service/ReadAheadInputStream.java | 7 +- .../cds/sdm/service/SDMAdminServiceImpl.java | 4 +- .../sdm/service/SDMAttachmentsService.java | 3 +- .../sap/cds/sdm/service/SDMServiceImpl.java | 29 +++++-- .../handler/SDMAttachmentsServiceHandler.java | 85 ++++++++++++------- .../handler/SDMCustomServiceHandler.java | 3 +- .../com/sap/cds/sdm/utilities/SDMUtils.java | 10 ++- 10 files changed, 175 insertions(+), 78 deletions(-) diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java index b9955d81f..f89de2b80 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java @@ -98,10 +98,17 @@ public static Map getAttachmentPathMapping( processNestedAttachmentComposition( model, entity, reader, pathMapping, composition)); - logger.debug("Found {} attachment path mappings for entity: {}", pathMapping.size(), entity.getQualifiedName()); + logger.debug( + "Found {} attachment path mappings for entity: {}", + pathMapping.size(), + entity.getQualifiedName()); return pathMapping; } catch (Exception e) { - logger.error("Error fetching attachment composition for entity {}: {}", entity.getQualifiedName(), e.getMessage(), e); + logger.error( + "Error fetching attachment composition for entity {}: {}", + entity.getQualifiedName(), + e.getMessage(), + e); return new HashMap<>(); } } @@ -209,7 +216,10 @@ private static boolean isDirectAttachmentTargetAspect(String targetAspect) { */ public static List> fetchAttachments( String targetEntity, Map entity, String attachmentCompositionName) { - logger.debug("Fetching attachments for entity: {}, composition: {}", targetEntity, attachmentCompositionName); + logger.debug( + "Fetching attachments for entity: {}, composition: {}", + targetEntity, + attachmentCompositionName); String[] targetEntityPath = targetEntity.split("\\."); targetEntity = targetEntityPath[targetEntityPath.length - 1]; entity = AttachmentsHandlerUtils.wrapEntityWithParent(entity, targetEntity); @@ -222,9 +232,13 @@ public static List> fetchAttachments( : null; // Second last part (e.g., "chapters") // Find all attachment arrays in the nested entity structure - List> attachments = AttachmentsHandlerUtils.findNestedAttachments( - entity, attachmentKeyFromComposition, parentKeyFromComposition); - logger.debug("Fetched {} attachments for composition: {}", attachments.size(), attachmentCompositionName); + List> attachments = + AttachmentsHandlerUtils.findNestedAttachments( + entity, attachmentKeyFromComposition, parentKeyFromComposition); + logger.debug( + "Fetched {} attachments for composition: {}", + attachments.size(), + attachmentCompositionName); return attachments; } @@ -605,14 +619,17 @@ public static Boolean validateFileNames( isError = true; } if (restrictedFileNames != null && !restrictedFileNames.isEmpty()) { - logger.warn("File name validation failed: restricted characters in {} files", restrictedFileNames.size()); + logger.warn( + "File name validation failed: restricted characters in {} files", + restrictedFileNames.size()); context .getMessages() .error(SDMErrorMessages.nameConstraintMessage(restrictedFileNames) + contextInfo); isError = true; } if (duplicateFilenames != null && !duplicateFilenames.isEmpty()) { - logger.warn("File name validation failed: {} duplicate filenames found", duplicateFilenames.size()); + logger.warn( + "File name validation failed: {} duplicate filenames found", duplicateFilenames.size()); String formattedMessage = String.format( "%s%s", SDMErrorMessages.duplicateFilenameFormat(duplicateFilenames), contextInfo); @@ -656,11 +673,18 @@ public static void updateFilenameProperty( String fileNameInSDM, Map updatedSecondaryProperties) throws ServiceException { - logger.debug("Updating filename property - DB: {}, Request: {}, SDM: {}", fileNameInDB, filenameInRequest, fileNameInSDM); + logger.debug( + "Updating filename property - DB: {}, Request: {}, SDM: {}", + fileNameInDB, + filenameInRequest, + fileNameInSDM); if (fileNameInDB == null) { if (filenameInRequest != null) { if (!filenameInRequest.equals(fileNameInSDM)) { - logger.debug("Filename updated from SDM value: {} to request value: {}", fileNameInSDM, filenameInRequest); + logger.debug( + "Filename updated from SDM value: {} to request value: {}", + fileNameInSDM, + filenameInRequest); updatedSecondaryProperties.put("filename", filenameInRequest); } } else { @@ -672,7 +696,10 @@ public static void updateFilenameProperty( logger.warn("Filename validation failed: filename cannot be empty"); throw new ServiceException("Filename cannot be empty"); } else if (!fileNameInDB.equals(filenameInRequest)) { - logger.debug("Filename updated from DB value: {} to request value: {}", fileNameInDB, filenameInRequest); + logger.debug( + "Filename updated from DB value: {} to request value: {}", + fileNameInDB, + filenameInRequest); updatedSecondaryProperties.put("filename", filenameInRequest); } } @@ -744,7 +771,8 @@ public static void handleSDMUpdateResponse( attachment, fileNameInSDM, propertiesInDB, secondaryTypeProperties, descriptionInSDM); break; case 409: - logger.warn("SDM update failed with 409 Conflict (duplicate filename): {}", filenameInRequest); + logger.warn( + "SDM update failed with 409 Conflict (duplicate filename): {}", filenameInRequest); duplicateFileNameList.add(filenameInRequest); revertAttachmentProperties( attachment, fileNameInSDM, propertiesInDB, secondaryTypeProperties, descriptionInSDM); @@ -788,7 +816,8 @@ public static void handleSDMServiceException( String descriptionInSDM, List filesWithUnsupportedProperties, Map badRequest) { - logger.error("SDM service exception occurred for file {}: {}", filenameInRequest, e.getMessage()); + logger.error( + "SDM service exception occurred for file {}: {}", filenameInRequest, e.getMessage()); if (e.getMessage().startsWith(SDMUtils.getErrorMessage("UNSUPPORTED_PROPERTIES"))) { String unsupportedDetails = e.getMessage() @@ -851,7 +880,8 @@ public static void revertAttachmentProperties( */ public static CmisDocument prepareCmisDocument( String filenameInRequest, String descriptionInRequest, String objectId) { - logger.debug("Preparing CMIS document - filename: {}, objectId: {}", filenameInRequest, objectId); + logger.debug( + "Preparing CMIS document - filename: {}, objectId: {}", filenameInRequest, objectId); CmisDocument cmisDocument = new CmisDocument(); cmisDocument.setFileName(filenameInRequest); cmisDocument.setDescription(descriptionInRequest); diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java index b35500c2d..8196cb343 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java +++ b/sdm/src/main/java/com/sap/cds/sdm/handler/common/SDMAttachmentsReader.java @@ -60,7 +60,8 @@ public List readAttachments( Result result = persistence.run(select); List attachmentsList = result.listOf(Attachments.class); - logger.info("Read {} attachments for entity: {}", attachmentsList.size(), entity.getQualifiedName()); + logger.info( + "Read {} attachments for entity: {}", attachmentsList.size(), entity.getQualifiedName()); logger.debug("END: Reading attachments"); return attachmentsList; } @@ -115,7 +116,7 @@ private List> buildExpandList(SDMNodeTree root) { logger.debug("Root node is null, returning empty expand list"); return expandResultList; } - + root.getChildren() .forEach( child -> { diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java b/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java index 4c608f589..e2d2af0a7 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/DocumentUploadService.java @@ -59,28 +59,35 @@ public JSONObject createDocument( AttachmentCreateEventContext eventContext) throws IOException { long startTime = System.currentTimeMillis(); - logger.info("START: Create document - fileName: {}, fileSize: {} bytes", - cmisDocument.getFileName(), cmisDocument.getContentLength()); - logger.debug("Document properties - repositoryId: {}, mimeType: {}", - cmisDocument.getRepositoryId(), cmisDocument.getMimeType()); - + logger.info( + "START: Create document - fileName: {}, fileSize: {} bytes", + cmisDocument.getFileName(), + cmisDocument.getContentLength()); + logger.debug( + "Document properties - repositoryId: {}, mimeType: {}", + cmisDocument.getRepositoryId(), + cmisDocument.getMimeType()); + try { if ("application/internet-shortcut".equalsIgnoreCase(cmisDocument.getMimeType())) { logger.info("LinkType detected, uploading as single chunk"); JSONObject result = uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); - logger.info("Link file uploaded successfully in {} ms", (System.currentTimeMillis() - startTime)); + logger.info( + "Link file uploaded successfully in {} ms", (System.currentTimeMillis() - startTime)); return result; } long totalSize = cmisDocument.getContentLength(); int chunkSize = SDMConstants.CHUNK_SIZE; cmisDocument.setUploadStatus(SDMConstants.UPLOAD_STATUS_IN_PROGRESS); logger.debug("Total file size: {} bytes, Chunk size: {} bytes", totalSize, chunkSize); - + if (totalSize <= 400 * 1024 * 1024) { // Upload directly if file is ≤ 400MB logger.info("File size is <= 400MB, uploading as single chunk"); JSONObject result = uploadSingleChunk(cmisDocument, sdmCredentials, isSystemUser); - logger.info("File uploaded successfully as single chunk in {} ms", (System.currentTimeMillis() - startTime)); + logger.info( + "File uploaded successfully as single chunk in {} ms", + (System.currentTimeMillis() - startTime)); return result; } else { String sdmUrl = @@ -88,7 +95,9 @@ public JSONObject createDocument( // Upload in chunks if file is > 400MB logger.info("File size is > 400MB, uploading in chunks of {} bytes", chunkSize); JSONObject result = uploadLargeFileInChunks(cmisDocument, sdmUrl, chunkSize, isSystemUser); - logger.info("File uploaded successfully in chunks in {} ms", (System.currentTimeMillis() - startTime)); + logger.info( + "File uploaded successfully in chunks in {} ms", + (System.currentTimeMillis() - startTime)); return result; } } catch (Exception e) { @@ -106,7 +115,8 @@ private void executeHttpPost( logger.debug("START: executeHttpPost for file: {}", cmisDocument.getFileName()); try (CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(uploadFile)) { formResponse(cmisDocument, finalResponse, response); - logger.debug("END: executeHttpPost - response formed for file: {}", cmisDocument.getFileName()); + logger.debug( + "END: executeHttpPost - response formed for file: {}", cmisDocument.getFileName()); } catch (IOException e) { throw new ServiceException(SDMUtils.getErrorMessage("ERROR_IN_SETTING_TIMEOUT"), e); } @@ -126,7 +136,8 @@ private JSONObject appendContentStream( throws IOException, ParseException { long startTime = System.currentTimeMillis(); - logger.debug("Appending chunk {} with {} bytes, isLastChunk: {}", chunkIndex, bytesRead, isLastChunk); + logger.debug( + "Appending chunk {} with {} bytes, isLastChunk: {}", chunkIndex, bytesRead, isLastChunk); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addTextBody("cmisaction", "appendContent"); @@ -188,7 +199,9 @@ private JSONObject createEmptyDocument( Map finalResponse = new HashMap<>(); executeHttpPost(httpClient, request, cmisDocument, finalResponse); - logger.debug("END: createEmptyDocument - empty document created for file: {}", cmisDocument.getFileName()); + logger.debug( + "END: createEmptyDocument - empty document created for file: {}", + cmisDocument.getFileName()); return new JSONObject(finalResponse); } @@ -248,7 +261,10 @@ public JSONObject uploadSingleChunk( private JSONObject uploadLargeFileInChunks( CmisDocument cmisDocument, String sdmUrl, int chunkSize, boolean isSystemUser) throws IOException { - logger.debug("START: uploadLargeFileInChunks for file: {}, chunkSize: {}", cmisDocument.getFileName(), chunkSize); + logger.debug( + "START: uploadLargeFileInChunks for file: {}, chunkSize: {}", + cmisDocument.getFileName(), + chunkSize); try (ReadAheadInputStream chunkedStream = new ReadAheadInputStream(cmisDocument.getContent(), cmisDocument.getContentLength())) { @@ -337,7 +353,10 @@ private JSONObject uploadLargeFileInChunks( hasMoreChunks = false; } } - logger.debug("END: uploadLargeFileInChunks - completed {} chunks for file: {}", chunkIndex, cmisDocument.getFileName()); + logger.debug( + "END: uploadLargeFileInChunks - completed {} chunks for file: {}", + chunkIndex, + cmisDocument.getFileName()); return responseBody; } catch (Exception e) { logger.error("Exception in uploadLargeFileInChunks: {}", e.getMessage()); @@ -360,7 +379,7 @@ private void formResponse( String responseString = EntityUtils.toString(response.getEntity()); int responseCode = response.getStatusLine().getStatusCode(); logger.debug("SDM response code: {} for file: {}", responseCode, name); - + if (responseCode == 201 || responseCode == 200) { logger.info("Document created successfully with response code: {}", responseCode); JSONObject jsonResponse = new JSONObject(responseString); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java b/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java index 65f6bd257..0ef108b33 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/ReadAheadInputStream.java @@ -216,7 +216,12 @@ public synchronized int read() throws IOException { @Override public synchronized int read(byte[] b, int off, int len) throws IOException { - logger.debug("read(byte[], off={}, len={}) called, position: {}, bufferSize: {}", off, len, position.get(), currentBufferSize); + logger.debug( + "read(byte[], off={}, len={}) called, position: {}, bufferSize: {}", + off, + len, + position.get(), + currentBufferSize); if (position.get() >= currentBufferSize) { if (lastChunkLoaded.get()) return -1; loadNextChunk(); diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java index aaf8e3cfe..bc87a6763 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java +++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMAdminServiceImpl.java @@ -38,7 +38,9 @@ public class SDMAdminServiceImpl implements SDMAdminService { @java.lang.Override public String onboardRepository(Repository repository) throws JsonProcessingException, UnsupportedEncodingException { - logger.debug("START: onboardRepository for repository: {}", repository != null ? repository.getDisplayName() : "null"); + logger.debug( + "START: onboardRepository for repository: {}", + repository != null ? repository.getDisplayName() : "null"); if (repository == null) { logger.error("Repository object is null. Cannot proceed with onboarding."); throw new IllegalArgumentException("Repository object cannot be null."); 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 32577f009..6fd663b7f 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 @@ -140,7 +140,8 @@ public Map moveAttachments(MoveAttachmentInput input, boolean is // Return structured result that OData can serialize Map result = new HashMap<>(); result.put("failedAttachments", failedAttachments != null ? failedAttachments : List.of()); - logger.debug("END: moveAttachments - returning result with {} failed attachments", + logger.debug( + "END: moveAttachments - returning result with {} failed attachments", failedAttachments != null ? failedAttachments.size() : 0); return result; } 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 bb7cea4e3..46e6cb55f 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 @@ -588,8 +588,10 @@ public RepoValue checkRepositoryType(String repositoryId, String tenant) { repoKey.setSubdomain(tenant); repoKey.setRepoId(repositoryId); RepoValue value = repoValueMap.get(repositoryId); - logger.debug("Repository info fetched - VersionEnabled: {}, VirusScanEnabled: {}", - value.getVersionEnabled(), value.getVirusScanEnabled()); + logger.debug( + "Repository info fetched - VersionEnabled: {}, VirusScanEnabled: {}", + value.getVersionEnabled(), + value.getVirusScanEnabled()); CacheConfig.getRepoCache().put(repoKey, value); return repoValueMap.get(repositoryId); } @@ -608,7 +610,9 @@ public JSONObject getRepositoryInfo(SDMCredentials sdmCredentials) { HttpGet getRepoInfoRequest = new HttpGet(getRepoInfoUrl); try (var response = (CloseableHttpResponse) httpClient.execute(getRepoInfoRequest)) { if (response.getStatusLine().getStatusCode() != 200) { - logger.error("Failed to fetch repository info. Status code: {}", response.getStatusLine().getStatusCode()); + logger.error( + "Failed to fetch repository info. Status code: {}", + response.getStatusLine().getStatusCode()); throw new ServiceException(SDMUtils.getErrorMessage("REPOSITORY_ERROR")); } String responseString = EntityUtils.toString(response.getEntity()); @@ -649,14 +653,17 @@ public Map fetchRepositoryData(JSONObject repoInfo, String re } } repoValueMap.put(repositoryId, repoValue); - logger.debug("END: fetchRepositoryData - VersionEnabled: {}, VirusScanEnabled: {}", - repoValue.getVersionEnabled(), repoValue.getVirusScanEnabled()); + logger.debug( + "END: fetchRepositoryData - VersionEnabled: {}, VirusScanEnabled: {}", + repoValue.getVersionEnabled(), + repoValue.getVirusScanEnabled()); return repoValueMap; } @Override public int deleteDocument(String cmisaction, String objectId, String user) { - logger.info("Deleting document - action: {}, objectId: {}, user: {}", cmisaction, objectId, user); + logger.info( + "Deleting document - action: {}, objectId: {}, user: {}", cmisaction, objectId, user); long startTime = System.currentTimeMillis(); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); HttpClient httpClient; @@ -678,8 +685,10 @@ public int deleteDocument(String cmisaction, String objectId, String user) { deleteDocumentRequest.setEntity(multipart); try (var response = (CloseableHttpResponse) httpClient.execute(deleteDocumentRequest)) { int statusCode = response.getStatusLine().getStatusCode(); - logger.info("Document deletion completed with status code: {} in {} ms", - statusCode, (System.currentTimeMillis() - startTime)); + logger.info( + "Document deletion completed with status code: {} in {} ms", + statusCode, + (System.currentTimeMillis() - startTime)); return statusCode; } catch (IOException e) { logger.error("Error deleting document {}: {}", objectId, e.getMessage(), e); @@ -777,7 +786,9 @@ public List getValidSecondaryProperties( } } } - logger.debug("END: getValidSecondaryProperties - found {} valid properties", validSecondaryProperties.size()); + logger.debug( + "END: getValidSecondaryProperties - found {} valid properties", + validSecondaryProperties.size()); return validSecondaryProperties; } 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 05ddd06dc..420214536 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 @@ -58,18 +58,18 @@ public SDMAttachmentsServiceHandler( @On(event = AttachmentService.EVENT_CREATE_ATTACHMENT) public void createAttachment(AttachmentCreateEventContext context) throws IOException { long startTime = System.currentTimeMillis(); - String contentLength = (context.getParameterInfo() != null && context.getParameterInfo().getHeaders() != null) - ? context.getParameterInfo().getHeaders().get("content-length") - : null; + String contentLength = + (context.getParameterInfo() != null && context.getParameterInfo().getHeaders() != null) + ? context.getParameterInfo().getHeaders().get("content-length") + : null; logger.info( - "CREATE_ATTACHMENT Event Received with content length {} At {}", - contentLength, - startTime); - logger.debug("User: {}, Tenant: {}", context.getUserInfo().getId(), context.getUserInfo().getTenant()); - + "CREATE_ATTACHMENT Event Received with content length {} At {}", contentLength, startTime); + logger.debug( + "User: {}, Tenant: {}", context.getUserInfo().getId(), context.getUserInfo().getTenant()); + validateRepository(context); logger.debug("Repository validation completed"); - + processEntities(context); long endTime = System.currentTimeMillis(); logger.info("CREATE_ATTACHMENT completed successfully in {} ms", (endTime - startTime)); @@ -85,13 +85,17 @@ public void markAttachmentAsDeleted(AttachmentMarkAsDeletedEventContext context) String objectId = contextValues[0]; String folderId = contextValues[1]; String entity = contextValues[2]; - logger.debug("Processing deletion - objectId: {}, folderId: {}, entity: {}", objectId, folderId, entity); - + logger.debug( + "Processing deletion - objectId: {}, folderId: {}, entity: {}", + objectId, + folderId, + entity); + // check if only attachment exists against the folderId List cmisDocuments = dbQuery.getAttachmentsForFolder(entity, persistenceService, folderId, context); logger.debug("Found {} attachments for folder: {}", cmisDocuments.size(), folderId); - + if (cmisDocuments.isEmpty()) { // deleteFolder API logger.info("Deleting folder: {} for entity: {}", folderId, entity); @@ -127,12 +131,12 @@ public void readAttachment(AttachmentReadEventContext context) throws IOExceptio String objectId = contentIdParts[0]; String entity = contentIdParts.length > 2 ? contentIdParts[2] : contentIdParts[0]; logger.debug("Reading attachment - objectId: {}, entity: {}", objectId, entity); - + SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); CmisDocument cmisDocument = dbQuery.getuploadStatusForAttachment(entity, persistenceService, objectId, context); logger.debug("Attachment upload status: {}", cmisDocument.getUploadStatus()); - + if (cmisDocument.getUploadStatus() != null && cmisDocument .getUploadStatus() @@ -146,14 +150,19 @@ public void readAttachment(AttachmentReadEventContext context) throws IOExceptio throw new ServiceException(SDMUtils.getErrorMessage("VIRUS_SCAN_IN_PROGRESS_FILE_ERROR")); } if (cmisDocument.getUploadStatus() != null - && cmisDocument.getUploadStatus().equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) { + && cmisDocument + .getUploadStatus() + .equalsIgnoreCase(SDMConstants.UPLOAD_STATUS_IN_PROGRESS)) { logger.warn("Upload is in progress for attachment: {}", objectId); throw new ServiceException(SDMUtils.getErrorMessage("UPLOAD_IN_PROGRESS_FILE_ERROR")); } try { logger.info("Initiating document read from repository for objectId: {}", objectId); sdmService.readDocument(objectId, sdmCredentials, context); - logger.info("Document read completed for objectId: {} in {} ms", objectId, (System.currentTimeMillis() - startTime)); + logger.info( + "Document read completed for objectId: {} in {} ms", + objectId, + (System.currentTimeMillis() - startTime)); } catch (Exception e) { logger.error("Error reading document {} from repository: {}", objectId, e.getMessage(), e); throw new ServiceException(e.getMessage()); @@ -209,17 +218,20 @@ private void validateRepository(AttachmentCreateEventContext eventContext) logger.debug("Checking repository type for: {}", repositoryId); RepoValue repoValue = sdmService.checkRepositoryType(repositoryId, eventContext.getUserInfo().getTenant()); - + if (repoValue.getVersionEnabled()) { logger.warn("Repository is versioned which is not allowed: {}", repositoryId); throw new ServiceException(SDMUtils.getErrorMessage("VERSIONED_REPO_ERROR")); } - + String len = eventContext.getParameterInfo().getHeaders().get("content-length"); long contentLen = !StringUtils.isEmpty(len) ? Long.parseLong(len) : -1; - logger.debug("Content length: {} bytes, Async virus scan enabled: {}, Virus scan enabled: {}", - contentLen, repoValue.getIsAsyncVirusScanEnabled(), repoValue.getVirusScanEnabled()); - + logger.debug( + "Content length: {} bytes, Async virus scan enabled: {}, Virus scan enabled: {}", + contentLen, + repoValue.getIsAsyncVirusScanEnabled(), + repoValue.getVirusScanEnabled()); + // Check if repository is virus scanned if (!repoValue.getIsAsyncVirusScanEnabled() && repoValue.getVirusScanEnabled() @@ -279,7 +291,7 @@ private void checkAttachmentConstraints( Long maxCount = SDMUtils.getAttachmentCountAndMessage( eventContext.getModel().entities().toList(), eventContext.getAttachmentEntity()); - + logger.debug("Current attachment count: {}, Max allowed count: {}", rowCount, maxCount); if (maxCount > 0 && rowCount >= maxCount) { logger.warn("Attachment count exceeds maximum limit: {} >= {}", rowCount, maxCount); @@ -325,16 +337,20 @@ private void createDocumentInSDM( String repositoryId = SDMConstants.REPOSITORY_ID; String entityName = eventContext.getAttachmentEntity().getQualifiedName().split("\\.")[2]; String folderName = upID + "__" + entityName; - logger.debug("Creating folder structure - folderName: {}, isSystemUser: {}", folderName, isSystemUser); - + logger.debug( + "Creating folder structure - folderName: {}, isSystemUser: {}", folderName, isSystemUser); + String folderId = sdmService.getFolderId(result, persistenceService, folderName, isSystemUser); logger.debug("Obtained folderId: {} for folder: {}", folderId, folderName); - + String len = eventContext.getParameterInfo().getHeaders().get("content-length"); long contentLen = !StringUtils.isEmpty(len) ? Long.parseLong(len) : -1; setCmisDocumentProperties( cmisDocument, data, attachmentIds, folderId, repositoryId, upIdKey, contentLen); - logger.debug("CMIS document properties set - fileName: {}, contentLength: {}", data.getFileName(), contentLen); + logger.debug( + "CMIS document properties set - fileName: {}, contentLength: {}", + data.getFileName(), + contentLen); SDMCredentials sdmCredentials = tokenHandler.getSDMCredentials(); JSONObject createResult = null; @@ -342,14 +358,19 @@ private void createDocumentInSDM( logger.info("Initiating document creation in SDM repository"); createResult = documentService.createDocument(cmisDocument, sdmCredentials, isSystemUser, eventContext); - logger.debug("Document creation response received: {}", createResult != null ? createResult.toString() : "null"); + logger.debug( + "Document creation response received: {}", + createResult != null ? createResult.toString() : "null"); } catch (Exception e) { logger.error("Error creating document in SDM service: {}", e.getMessage(), e); throw new ServiceException( SDMErrorMessages.getGenericError(AttachmentService.EVENT_CREATE_ATTACHMENT), e); } - - logger.info("Upload Finished at: {} (duration: {} ms)", System.currentTimeMillis(), (System.currentTimeMillis() - startTime)); + + logger.info( + "Upload Finished at: {} (duration: {} ms)", + System.currentTimeMillis(), + (System.currentTimeMillis() - startTime)); handleCreateDocumentResult(cmisDocument, createResult, eventContext); logger.debug("END: Create document in SDM"); } @@ -408,8 +429,10 @@ private void handleCreateDocumentResult( (createResult.get("uploadStatus") != null) ? createResult.get("uploadStatus").toString() : SDMConstants.UPLOAD_STATUS_IN_PROGRESS); - logger.info("Document created successfully with objectId: {} and status: {}", - cmisDocument.getObjectId(), cmisDocument.getUploadStatus()); + logger.info( + "Document created successfully with objectId: {} and status: {}", + cmisDocument.getObjectId(), + cmisDocument.getUploadStatus()); dbQuery.addAttachmentToDraft( getAttachmentDraftEntity(eventContext), persistenceService, cmisDocument); finalizeContext(eventContext, 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 9b15982ea..6cd9b795b 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 @@ -1527,7 +1527,8 @@ private void handleCopyFailure( logger.debug("Deleting newly created folder: {}", folderId); sdmService.deleteDocument("deleteTree", folderId, context.getUserInfo().getName()); } else { - logger.debug("Deleting {} copied attachments from existing folder", attachmentsMetadata.size()); + logger.debug( + "Deleting {} copied attachments from existing folder", attachmentsMetadata.size()); for (Map attachmentMetadata : attachmentsMetadata) { sdmService.deleteDocument( "delete", attachmentMetadata.get("cmis:objectId"), context.getUserInfo().getName()); diff --git a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java index 91a9c4bdf..7294d7771 100644 --- a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java +++ b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java @@ -65,7 +65,8 @@ public static Set FileNameContainsWhitespace( } } } - logger.debug("END: FileNameContainsWhitespace - found {} issues", filenamesWithWhitespace.size()); + logger.debug( + "END: FileNameContainsWhitespace - found {} issues", filenamesWithWhitespace.size()); return filenamesWithWhitespace; } @@ -117,7 +118,9 @@ public static List FileNameContainsRestrictedCharaters( } } } - logger.debug("END: FileNameContainsRestrictedCharaters - found {} restricted", restrictedFilenames.size()); + logger.debug( + "END: FileNameContainsRestrictedCharaters - found {} restricted", + restrictedFilenames.size()); return restrictedFilenames; } @@ -432,7 +435,8 @@ public static Map getUpdatedSecondaryProperties( public static Long getAttachmentCountAndMessage( List entities, CdsEntity attachmentEntity) { - logger.debug("START: getAttachmentCountAndMessage for entity: {}", attachmentEntity.getQualifiedName()); + logger.debug( + "START: getAttachmentCountAndMessage for entity: {}", attachmentEntity.getQualifiedName()); Long maxCount = CacheConfig.getMaxAllowedAttachmentsCache().get(attachmentEntity.getQualifiedName());