I have a problem with the uploader. When I upload multiple files it can happen that on or multiple files already exists. If this happens I want that the uploader interrupts and a dialof is opened where the user can select if he want to overwrite the file (in my case a new version is created), the file should be stored using another name or the upload of this current file should be aborted. After the user made a decision by pressing the button, the upload should continue. I already tried with CompletableFuture but I am not able to get this work as expected. Can someone give me a hint?
This is my current code:
public CmisMultiFileUploader(DmsAbstractController dmsController, DmsScope scope, Organization organization, AutoUpdateComponent component) {
this.uploadCounter = 0;
this.tempFiles = new ConcurrentHashMap<>();
this.setWidth(100, Unit.PERCENTAGE);
MultiFileReceiver receiver = (fileName, mimeType) -> {
try {
parentFolder = dmsController.getCurrentFolder();
if (parentFolder == null) {
displayDialog("No parent folder selected, cannot upload file(s)!");
throw new IllegalStateException("No parent folder selected");
}
File tempFile = File.createTempFile("upload-", fileName);
tempFiles.put(fileName, tempFile);
OutputStream outputStream = new FileOutputStream(tempFile);
upload.addSucceededListener(event -> {
CompletableFuture<Void> decisionFuture = new CompletableFuture<>();
try {
try (InputStream inputStream = new FileInputStream(tempFile)) {
dmsController.storeDmsFile(DmsUploadOperation.UPLOAD, scope, parentFolder.getFolder(), fileName, mimeType, inputStream);
uploadCounter++;
decisionFuture.complete(null); // Upload successful, no conflicts
} catch (DocumentAlreadyExistsInFolder | CmisContentAlreadyExistsException e) {
// Handle file conflict with a blocking dialog
handleFileConflict(dmsController, scope, parentFolder.getFolder(), fileName, mimeType, tempFile, decisionFuture);
} catch (IOException | FolderNotInDmsScopeException | DmsScopeNullValueException e) {
decisionFuture.completeExceptionally(e);
}
} finally {
// Wait for decisionFuture before cleaning up
decisionFuture.whenComplete((result, exception) -> {
// Cleanup after the decision is made
if (exception != null) {
log.error("Error during file upload decision-making", exception);
}
tempFiles.remove(fileName);
if (tempFile.exists() && !tempFile.delete()) {
log.warn("Failed to delete temporary file: " + tempFile.getAbsolutePath());
}
clear();
});
}
});
return outputStream;
} catch (Exception e) {
log.error("Error initializing upload receiver for file: " + fileName, e);
return null;
}
};
upload = new Upload(receiver);
upload.setMaxFileSize((int) dmsController.getMaxUploadSizeInByte());
upload.setI18n(I18n.getUploadI18n(organization));
upload.setDropAllowed(true);
this.add(upload);
upload.addFailedListener(event -> {
displayDialog(event.getReason().getMessage());
});
upload.addStartedListener(event -> {
log.debug("File upload started.");
});
upload.addProgressListener(event -> {
//System.out.println("Progress");
});
upload.addFinishedListener(event -> {
log.debug("File upload finished.");
if(component != null)
component.updateComponent();
});
upload.addFileRejectedListener(event -> {
displayDialog(event.getErrorMessage());
});
upload.addAllFinishedListener(event -> {
log.debug("All file uploads finished.");
DefaultNotification.show(AppIcon.ok(), uploadCounter +" Datei(en) erfolgreich hochgeladen.");
// Clear the upload form
clear();
//
// Update the Autocomponent
//
if(component != null)
component.updateComponent();
});
}
private void handleFileConflict(DmsAbstractController dmsController, DmsScope scope, Folder parentFolder, String fileName, String mimeType, File tempFile, CompletableFuture<Void> decisionFuture) {
// Open the conflict dialog
UploadSelectionDialog uploadSelectionDialog = new UploadSelectionDialog(fileName);
// New Version Option
uploadSelectionDialog.addNewVersionListener(newVersion -> {
try (InputStream inputStream = new FileInputStream(tempFile)) { // Use try-with-resources
dmsController.storeDmsFile(DmsUploadOperation.NEW_VERSION, scope, parentFolder, fileName, mimeType, inputStream);
uploadSelectionDialog.close();
uploadCounter++;
log.debug("Uploaded as a new version: " + fileName);
} catch (Exception e) {
log.error("Error uploading as new version: " + fileName, e);
displayDialog("An error occurred while uploading " + fileName + " as a new version.");
} finally {
decisionFuture.complete(null); // Signal completion
}
});
// Keep Both Option
uploadSelectionDialog.addKeepBothListener(keepBoth -> {
try (InputStream inputStream = new FileInputStream(tempFile)) {
dmsController.storeDmsFile(DmsUploadOperation.KEEP_BOTH, scope, parentFolder, fileName, mimeType, inputStream);
uploadSelectionDialog.close();
uploadCounter++;
log.debug("Uploaded with 'Keep Both' option: " + fileName);
} catch (Exception e) {
log.error("Error uploading with 'Keep Both' option: " + fileName, e);
displayDialog("An error occurred while keeping both versions of " + fileName);
} finally {
decisionFuture.complete(null); // Signal completion
}
});
// Cancel Option
uploadSelectionDialog.addCancelListener(cancel -> {
try {
dmsController.storeDmsFile(DmsUploadOperation.ABORT, scope, parentFolder, fileName, mimeType, null);
uploadSelectionDialog.close();
log.debug("Upload canceled for: " + fileName);
} catch (Exception e) {
log.error("Error during upload cancellation: " + fileName, e);
displayDialog("An error occurred while canceling the upload of " + fileName);
} finally {
decisionFuture.complete(null); // Signal completion
}
});
// Open the dialog for user action
uploadSelectionDialog.open();
}
Thank you,
Florian