diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java index 834246c63..ed4e22ba0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadHandler.java @@ -89,6 +89,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public final OutputStream getOutputStream() { try { + view.getDuplicateFileNamesList().clear(); return view.saveUploadedFileDetails(fileName, fileSize, mimeType); } catch (final ArtifactUploadFailedException e) { LOG.error("Atifact upload failed {} ", e); @@ -108,6 +109,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene public OutputStream receiveUpload(final String fileName, final String mimeType) { this.fileName = fileName; this.mimeType = mimeType; + view.getDuplicateFileNamesList().clear(); try { if (view.validate()) { if (view.checkForDuplicate(fileName)) { @@ -167,7 +169,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene view.updateActionCount(); // display the duplicate message after streaming all files - view.displayDuplicateMessageAfterStreamingAll(); + view.displayValidationMessage(); } /** @@ -292,7 +294,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene if (view.enableProcessBtn()) { infoWindow.uploadSessionFinished(); } - view.displayDuplicateMessageAfterStreamingAll(); + view.displayValidationMessage(); LOG.info("Streaming failed due to :{}", event.getException()); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java index e570c84c4..b944006ff 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadLayout.java @@ -46,6 +46,7 @@ import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.annotation.EventBusListenerMethod; +import com.google.common.base.Strings; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.acceptcriteria.AcceptAll; @@ -70,529 +71,563 @@ import com.vaadin.ui.VerticalLayout; /** * Upload files layout. * - * + * @author G Venkata Narayana (RBEI/BSO3) */ @ViewScope @SpringComponent public class UploadLayout extends VerticalLayout { - private static final long serialVersionUID = -566164756606779220L; + private static final long serialVersionUID = -566164756606779220L; - private static final Logger LOG = LoggerFactory.getLogger(UploadLayout.class); + private static final Logger LOG = LoggerFactory.getLogger(UploadLayout.class); - @Autowired - private UploadStatusInfoWindow uploadInfoWindow; + @Autowired + private UploadStatusInfoWindow uploadInfoWindow; - @Autowired - private I18N i18n; + @Autowired + private I18N i18n; - @Autowired - private transient UINotification uiNotification; + @Autowired + private transient UINotification uiNotification; - @Autowired - private transient EventBus.SessionEventBus eventBus; + @Autowired + private transient EventBus.SessionEventBus eventBus; - @Autowired - private ArtifactUploadState artifactUploadState; + @Autowired + private ArtifactUploadState artifactUploadState; - @Autowired - private transient SPInfo spInfo; + @Autowired + private transient SPInfo spInfo; - private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); + private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); - private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); + private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); - private final List duplicateFileNamesList = new ArrayList(); - - private Button processBtn; - - private Button discardBtn; - - private UploadConfirmationwindow currentUploadConfirmationwindow; - - private VerticalLayout dropAreaLayout; - - private UI ui; - - private HorizontalLayout fileUploadLayout; - - private DragAndDropWrapper dropAreaWrapper; - - /** - * Initialize the upload layout. - */ - @PostConstruct - void init() { - createComponents(); - buildLayout(); - updateActionCount(); - eventBus.subscribe(this); - ui = UI.getCurrent(); - } - - private void createComponents() { - - createProcessButton(); - createDiscardBtn(); - } - - private void buildLayout() { - - final Upload upload = new Upload(); - final UploadHandler uploadHandler = new UploadHandler(null, 0, this, uploadInfoWindow, - spInfo.getMaxArtifactFileSize(), upload, null); - upload.setButtonCaption(i18n.get("upload.file")); - upload.setImmediate(true); - upload.setReceiver(uploadHandler); - upload.addSucceededListener(uploadHandler); - upload.addFailedListener(uploadHandler); - upload.addFinishedListener(uploadHandler); - upload.addProgressListener(uploadHandler); - upload.addStartedListener(uploadHandler); - upload.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); - - fileUploadLayout = new HorizontalLayout(); - fileUploadLayout.setSpacing(true); - fileUploadLayout.addComponent(upload); - fileUploadLayout.setComponentAlignment(upload, Alignment.MIDDLE_LEFT); - fileUploadLayout.addComponent(processBtn); - fileUploadLayout.setComponentAlignment(processBtn, Alignment.MIDDLE_RIGHT); - fileUploadLayout.addComponent(discardBtn); - fileUploadLayout.setComponentAlignment(discardBtn, Alignment.MIDDLE_RIGHT); - setMargin(false); - - /* create drag-drop wrapper for drop area */ - dropAreaWrapper = new DragAndDropWrapper(createDropAreaLayout()); - dropAreaWrapper.setDropHandler(new DropAreahandler()); - setSizeFull(); - setSpacing(true); - - } - - public DragAndDropWrapper getDropAreaWrapper() { - return dropAreaWrapper; - } - - private class DropAreahandler implements DropHandler { - - private static final long serialVersionUID = 1L; - - @Override - public AcceptCriterion getAcceptCriterion() { - return AcceptAll.get(); - } - - @Override - public void drop(final DragAndDropEvent event) { - if (validate()) { - - final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles(); - if (files != null) { - for (final Html5File file : files) { - if (!checkForDuplicate(file.getFileName())) { - numberOfFileUploadsExpected.incrementAndGet(); - file.setStreamVariable(createStreamVariable(file)); - } - } - if (numberOfFileUploadsExpected.get() > 0) { - processBtn.setEnabled(false); - // reset before we start - uploadInfoWindow.uploadSessionStarted(); - } - // in case if all selected files are duplicate ,then display - // message - displayDuplicateMessageAfterStreamingAll(); - } - } - } - } - - private VerticalLayout createDropAreaLayout() { - dropAreaLayout = new VerticalLayout(); - final Label dropHereLabel = new Label("Drop files to upload"); - dropHereLabel.setWidth(null); - - final Label dropIcon = new Label(FontAwesome.ARROW_DOWN.getHtml(), ContentMode.HTML); - dropIcon.addStyleName("drop-icon"); - dropIcon.setWidth(null); - - dropAreaLayout.addComponent(dropIcon); - dropAreaLayout.setComponentAlignment(dropIcon, Alignment.BOTTOM_CENTER); - dropAreaLayout.addComponent(dropHereLabel); - dropAreaLayout.setComponentAlignment(dropHereLabel, Alignment.TOP_CENTER); - dropAreaLayout.setSizeFull(); - dropAreaLayout.setStyleName("upload-drop-area-layout-info"); - dropAreaLayout.setSpacing(false); - return dropAreaLayout; - } - - private void createProcessButton() { - processBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON, - SPUILabelDefinitions.PROCESS, SPUILabelDefinitions.PROCESS, null, false, null, - SPUIButtonStyleSmall.class); - processBtn.setIcon(FontAwesome.BELL); - processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); - processBtn.addClickListener(event -> displayConfirmWindow(event)); - processBtn.setHtmlContentAllowed(true); - if (artifactUploadState.getFileSelected().isEmpty()) { - processBtn.setEnabled(false); - } - } - - private void createDiscardBtn() { - discardBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_DISCARD_BUTTON, - SPUILabelDefinitions.DISCARD, SPUILabelDefinitions.DISCARD, null, false, null, - SPUIButtonStyleSmall.class); - discardBtn.setIcon(FontAwesome.TRASH_O); - discardBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); - discardBtn.addClickListener(event -> discardUploadData(event)); - } - - private StreamVariable createStreamVariable(final Html5File file) { - return new UploadHandler(file.getFileName(), file.getFileSize(), this, uploadInfoWindow, - spInfo.getMaxArtifactFileSize(), null, file.getType()); - } - - boolean checkForDuplicate(final String filename) { - final Boolean isDuplicate = checkIfFileIsDuplicate(filename); - if (isDuplicate) { - getDuplicateFileNamesList().add(filename); - } - return isDuplicate; - } - - @EventBusListenerMethod(scope = EventScope.SESSION) - void toggleProcessButton(final UploadArtifactUIEvent event) { - if (event == UploadArtifactUIEvent.ENABLE_PROCESS_BUTTON) { - processBtn.setEnabled(true); - } else if (event == UploadArtifactUIEvent.DISABLE_PROCESS_BUTTON) { - processBtn.setEnabled(false); - } - } - - /** - * Save uploaded file details. - * - * @param stream - * read from uploaded file - * @param name - * file name - * @param size - * file size - * @param mimeType - * the mimeType of the file - * @throws IOException - * in case of upload errors - */ - OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType) { - File tempFile = null; - try { - tempFile = File.createTempFile("spUiArtifactUpload", null); - - final OutputStream out = new FileOutputStream(tempFile); - - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); - - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); - - final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(), - selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion(), mimeType); - - artifactUploadState.getFileSelected().add(customFile); - processBtn.setEnabled(false); - - if (!artifactUploadState.getBaseSwModuleList().keySet().contains(currentBaseSoftwareModuleKey)) { - artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSoftwareModule); - } - return out; - } catch (final FileNotFoundException e) { - LOG.error("Upload failed {}", e); - throw new ArtifactUploadFailedException(i18n.get("message.file.not.found")); - } catch (final IOException e) { - LOG.error("Upload failed {}", e); - throw new ArtifactUploadFailedException(i18n.get("message.upload.failed")); - } - } - - Boolean validate() { - if (!isSoftwareModuleSelected()) { - uiNotification.displayValidationError(i18n.get("message.error.noSwModuleSelected")); - - return false; - } - return true; - } - - SoftwareModule getSoftwareModuleSelected() { - if (artifactUploadState.getSelectedBaseSoftwareModule().isPresent()) { - return artifactUploadState.getSelectedBaseSoftwareModule().get(); - } - return null; - } - - Boolean isSoftwareModuleSelected() { - if (!artifactUploadState.getSelectedBaseSwModuleId().isPresent()) { - return false; - } - return true; - } - - /** - * Check if file selected is duplicate.i,e already selected for upload for - * same software module. - * - * @param name - * file name - * @return Boolean - */ - public Boolean checkIfFileIsDuplicate(final String name) { - Boolean isDuplicate = false; - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); - - for (final CustomFile customFile : artifactUploadState.getFileSelected()) { - final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( - customFile.getBaseSoftwareModuleName(), customFile.getBaseSoftwareModuleVersion()); - if (customFile.getFileName().equals(name) && currentBaseSoftwareModuleKey.equals(fileSoftwareModuleKey)) { - isDuplicate = true; - break; - } - } - return isDuplicate; - } - - void decreaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.decrementAndGet(); - } - - List getDuplicateFileNamesList() { - return duplicateFileNamesList; - } - - /** - * Update pending action count. - */ - void updateActionCount() { - if (!artifactUploadState.getFileSelected().isEmpty()) { - processBtn.setCaption(SPUILabelDefinitions.PROCESS + "
" - + artifactUploadState.getFileSelected().size() + "
"); - } else { - processBtn.setCaption(SPUILabelDefinitions.PROCESS); - } - } - - void displayDuplicateMessageAfterStreamingAll() { - // check if streaming of all dropped files are completed - if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) { - showDuplicateMessage(); - } - } - - /** - * Show duplicate file selected message. - */ - public void showDuplicateMessage() { - if (!duplicateFileNamesList.isEmpty()) { - final String fileNames = StringUtils.collectionToCommaDelimitedString(duplicateFileNamesList); - if (duplicateFileNamesList.size() == 1) { - uiNotification.displayValidationError(i18n.get("message.no.duplicateFile") + fileNames); - - } else if (duplicateFileNamesList.size() > 1) { - uiNotification.displayValidationError(i18n.get("message.no.duplicateFiles")); - } - duplicateFileNamesList.clear(); - } - } - - void increaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.incrementAndGet(); - } - - void updateFileSize(final String name, final long size) { - final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); - final String currentBaseSoftwareModuleKey = HawkbitCommonUtil - .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); - - for (final CustomFile customFile : artifactUploadState.getFileSelected()) { - final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( - customFile.getBaseSoftwareModuleName(), customFile.getBaseSoftwareModuleVersion()); - if (customFile.getFileName().equals(name) && currentBaseSoftwareModuleKey.equals(fileSoftwareModuleKey)) { - customFile.setFileSize(size); - break; - } - } - } - - void increaseNumberOfFilesActuallyUpload() { - numberOfFilesActuallyUpload.incrementAndGet(); - } - - /** - * Enable process button once upload is completed. - */ - boolean enableProcessBtn() { - if (numberOfFilesActuallyUpload.intValue() >= numberOfFileUploadsExpected.intValue()) { - processBtn.setEnabled(true); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); - return true; - } - return false; - } - - Set getFileSelected() { - return artifactUploadState.getFileSelected(); - } - - private void discardUploadData(final Button.ClickEvent event) { - if (event.getButton().equals(discardBtn)) { - if (artifactUploadState.getFileSelected().isEmpty()) { - uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); - - } else { - clearFileList(); - } - } - } - - /** - * Clear details. - */ - void clearFileList() { - // delete file system zombies - artifactUploadState.getFileSelected().forEach(customFile -> { - final File file = new File(customFile.getFilePath()); - file.delete(); - }); - - artifactUploadState.getFileSelected().clear(); - artifactUploadState.getBaseSwModuleList().clear(); - processBtn.setCaption(SPUILabelDefinitions.PROCESS); - /* disable when there is no files to upload. */ - processBtn.setEnabled(false); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); - duplicateFileNamesList.clear(); - } - - private void setConfirmationPopupHeightWidth(final float newWidth, final float newHeight) { - if (currentUploadConfirmationwindow != null) { - currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth(HawkbitCommonUtil - .getArtifactUploadPopupWidth(newWidth, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), - Unit.PIXELS); - currentUploadConfirmationwindow.getUploadDetailsTable().setHeight(HawkbitCommonUtil - .getArtifactUploadPopupHeight(newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), - Unit.PIXELS); - } - } - - /** - * Set artifact upload result pop up size changes. - * - * @param newWidth - * new width of result pop up - * @param newHeight - * new height of result pop up - */ - void setResultPopupHeightWidth(final float newWidth, final float newHeight) { - if (currentUploadConfirmationwindow != null - && currentUploadConfirmationwindow.getCurrentUploadResultWindow() != null) { - final UploadResultWindow uploadResultWindow = currentUploadConfirmationwindow - .getCurrentUploadResultWindow(); - uploadResultWindow.getUploadResultsWindow().setWidth(HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, - SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); - uploadResultWindow.getUploadResultTable().setHeight(HawkbitCommonUtil.getArtifactUploadPopupHeight( - newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); - } - } - - private void displayConfirmWindow(final Button.ClickEvent event) { - if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON)) { - if (artifactUploadState.getFileSelected().isEmpty()) { - uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); - } else { - currentUploadConfirmationwindow = new UploadConfirmationwindow(this, artifactUploadState); - UI.getCurrent().addWindow(currentUploadConfirmationwindow.getUploadConfrimationWindow()); - setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), - Page.getCurrent().getBrowserWindowHeight()); - } - } - } - - /** - * @return - */ - I18N getI18n() { - return i18n; - } - - /** - * @return - */ - SPInfo getSPInfo() { - return spInfo; - } - - void setCurrentUploadConfirmationwindow(final UploadConfirmationwindow currentUploadConfirmationwindow) { - this.currentUploadConfirmationwindow = currentUploadConfirmationwindow; - } - - /** - * @return - */ - - VerticalLayout getDropAreaLayout() { - return dropAreaLayout; - } - - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final UploadArtifactUIEvent event) { - if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { - ui.access(() -> updateActionCount()); - } - } - - @PreDestroy - void destroy() { - /* - * It's good manners to do this, even though vaadin-spring will - * automatically unsubscribe when this UI is garbage collected. - */ - eventBus.unsubscribe(this); - } - - /** - * set upload status and confirmation window. - * - * @param newWidth - * browser width - * @param newHeight - * browser height - */ - public void setUploadPopupSize(final float newWidth, final float newHeight) { - setConfirmationPopupHeightWidth(newWidth, newHeight); - setResultPopupHeightWidth(newWidth, newHeight); - } - - /** - * @param selectedBaseSoftwareModule - */ - public void refreshArtifactDetailsLayout(final SoftwareModule selectedBaseSoftwareModule) { - eventBus.publish(this, - new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, selectedBaseSoftwareModule)); - } - - /** - * @return the fileUploadLayout - */ - public HorizontalLayout getFileUploadLayout() { - return fileUploadLayout; - } - - public UINotification getUINotification() { - return uiNotification; - } + private final List duplicateFileNamesList = new ArrayList(); + + private Button processBtn; + + private Button discardBtn; + + private UploadConfirmationwindow currentUploadConfirmationwindow; + + private VerticalLayout dropAreaLayout; + + private UI ui; + + private HorizontalLayout fileUploadLayout; + + private DragAndDropWrapper dropAreaWrapper; + + private Boolean hasDirectory = Boolean.FALSE; + + /** + * Initialize the upload layout. + */ + @PostConstruct + void init() { + createComponents(); + buildLayout(); + updateActionCount(); + eventBus.subscribe(this); + ui = UI.getCurrent(); + } + + private void createComponents() { + + createProcessButton(); + createDiscardBtn(); + } + + private void buildLayout() { + + final Upload upload = new Upload(); + final UploadHandler uploadHandler = new UploadHandler(null, 0, this, uploadInfoWindow, + spInfo.getMaxArtifactFileSize(), upload, null); + upload.setButtonCaption(i18n.get("upload.file")); + upload.setImmediate(true); + upload.setReceiver(uploadHandler); + upload.addSucceededListener(uploadHandler); + upload.addFailedListener(uploadHandler); + upload.addFinishedListener(uploadHandler); + upload.addProgressListener(uploadHandler); + upload.addStartedListener(uploadHandler); + upload.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); + + fileUploadLayout = new HorizontalLayout(); + fileUploadLayout.setSpacing(true); + fileUploadLayout.addComponent(upload); + fileUploadLayout.setComponentAlignment(upload, Alignment.MIDDLE_LEFT); + fileUploadLayout.addComponent(processBtn); + fileUploadLayout.setComponentAlignment(processBtn, Alignment.MIDDLE_RIGHT); + fileUploadLayout.addComponent(discardBtn); + fileUploadLayout.setComponentAlignment(discardBtn, Alignment.MIDDLE_RIGHT); + setMargin(false); + + /* create drag-drop wrapper for drop area */ + dropAreaWrapper = new DragAndDropWrapper(createDropAreaLayout()); + dropAreaWrapper.setDropHandler(new DropAreahandler()); + setSizeFull(); + setSpacing(true); + + } + + public DragAndDropWrapper getDropAreaWrapper() { + return dropAreaWrapper; + } + + private class DropAreahandler implements DropHandler { + + private static final long serialVersionUID = 1L; + + @Override + public AcceptCriterion getAcceptCriterion() { + return AcceptAll.get(); + } + + @Override + public void drop(final DragAndDropEvent event) { + if (validate()) { + ((WrapperTransferable) event.getTransferable()).getDraggedComponent(); + final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles(); + if (files != null) { + for (final Html5File file : files) { + if (!isDirectory(file)) { + if (!checkForDuplicate(file.getFileName())) { + numberOfFileUploadsExpected.incrementAndGet(); + file.setStreamVariable(createStreamVariable(file)); + } + } else { + hasDirectory = Boolean.TRUE; + } + } + if (numberOfFileUploadsExpected.get() > 0) { + processBtn.setEnabled(false); + // reset before we start + uploadInfoWindow.uploadSessionStarted(); + } else { + //If the upload is not started, it signifies all dropped files as either duplicate or directory.So display message accordingly + displayCompositeMessage(hasDirectory); + } + } + } + } + } + + private static boolean isDirectory(final Html5File file) { + if (Strings.isNullOrEmpty(file.getType()) && file.getFileSize() % 4096 == 0) { + return true; + } + return false; + } + + private void displayCompositeMessage(final Boolean hasDirectory) { + final String duplicateMessage = showDuplicateMessage(); + final StringBuilder compositeMessage = new StringBuilder(); + if (null != duplicateMessage) { + // in case if all selected files are duplicate ,then display + // messag + compositeMessage.append(duplicateMessage); + } + if (hasDirectory) { + if (compositeMessage.length() > 0) { + compositeMessage.append("
"); + } + compositeMessage.append(i18n.get("message.no.directory.upload")); + } + if (!compositeMessage.toString().isEmpty()) { + uiNotification.displayValidationError(compositeMessage.toString()); + } + } + + private VerticalLayout createDropAreaLayout() { + dropAreaLayout = new VerticalLayout(); + final Label dropHereLabel = new Label("Drop files to upload"); + dropHereLabel.setWidth(null); + + final Label dropIcon = new Label(FontAwesome.ARROW_DOWN.getHtml(), ContentMode.HTML); + dropIcon.addStyleName("drop-icon"); + dropIcon.setWidth(null); + + dropAreaLayout.addComponent(dropIcon); + dropAreaLayout.setComponentAlignment(dropIcon, Alignment.BOTTOM_CENTER); + dropAreaLayout.addComponent(dropHereLabel); + dropAreaLayout.setComponentAlignment(dropHereLabel, Alignment.TOP_CENTER); + dropAreaLayout.setSizeFull(); + dropAreaLayout.setStyleName("upload-drop-area-layout-info"); + dropAreaLayout.setSpacing(false); + return dropAreaLayout; + } + + private void createProcessButton() { + processBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON, + SPUILabelDefinitions.PROCESS, SPUILabelDefinitions.PROCESS, null, false, null, + SPUIButtonStyleSmall.class); + processBtn.setIcon(FontAwesome.BELL); + processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); + processBtn.addClickListener(event -> displayConfirmWindow(event)); + processBtn.setHtmlContentAllowed(true); + if (artifactUploadState.getFileSelected().isEmpty()) { + processBtn.setEnabled(false); + } + } + + private void createDiscardBtn() { + discardBtn = SPUIComponentProvider.getButton(SPUIComponetIdProvider.UPLOAD_DISCARD_BUTTON, + SPUILabelDefinitions.DISCARD, SPUILabelDefinitions.DISCARD, null, false, null, + SPUIButtonStyleSmall.class); + discardBtn.setIcon(FontAwesome.TRASH_O); + discardBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); + discardBtn.addClickListener(event -> discardUploadData(event)); + } + + private StreamVariable createStreamVariable(final Html5File file) { + return new UploadHandler(file.getFileName(), file.getFileSize(), this, uploadInfoWindow, + spInfo.getMaxArtifactFileSize(), null, file.getType()); + } + + boolean checkForDuplicate(final String filename) { + final Boolean isDuplicate = checkIfFileIsDuplicate(filename); + if (isDuplicate) { + getDuplicateFileNamesList().add(filename); + } + return isDuplicate; + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void toggleProcessButton(final UploadArtifactUIEvent event) { + if (event == UploadArtifactUIEvent.ENABLE_PROCESS_BUTTON) { + processBtn.setEnabled(true); + } else if (event == UploadArtifactUIEvent.DISABLE_PROCESS_BUTTON) { + processBtn.setEnabled(false); + } + } + + /** + * Save uploaded file details. + * + * @param stream + * read from uploaded file + * @param name + * file name + * @param size + * file size + * @param mimeType + * the mimeType of the file + * @throws IOException + * in case of upload errors + */ + OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType) { + File tempFile = null; + try { + tempFile = File.createTempFile("spUiArtifactUpload", null); + + final OutputStream out = new FileOutputStream(tempFile); + + final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); + + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil + .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); + + final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(), + selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion(), mimeType); + + artifactUploadState.getFileSelected().add(customFile); + processBtn.setEnabled(false); + + if (!artifactUploadState.getBaseSwModuleList().keySet().contains(currentBaseSoftwareModuleKey)) { + artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSoftwareModule); + } + return out; + } catch (final FileNotFoundException e) { + LOG.error("Upload failed {}", e); + throw new ArtifactUploadFailedException(i18n.get("message.file.not.found")); + } catch (final IOException e) { + LOG.error("Upload failed {}", e); + throw new ArtifactUploadFailedException(i18n.get("message.upload.failed")); + } + } + + Boolean validate() { + if (!isSoftwareModuleSelected()) { + uiNotification.displayValidationError(i18n.get("message.error.noSwModuleSelected")); + return false; + } + return true; + } + + SoftwareModule getSoftwareModuleSelected() { + if (artifactUploadState.getSelectedBaseSoftwareModule().isPresent()) { + return artifactUploadState.getSelectedBaseSoftwareModule().get(); + } + return null; + } + + Boolean isSoftwareModuleSelected() { + if (!artifactUploadState.getSelectedBaseSwModuleId().isPresent()) { + return false; + } + return true; + } + + /** + * Check if file selected is duplicate.i,e already selected for upload for + * same software module. + * + * @param name + * file name + * @return Boolean + */ + public Boolean checkIfFileIsDuplicate(final String name) { + Boolean isDuplicate = false; + final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil + .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); + + for (final CustomFile customFile : artifactUploadState.getFileSelected()) { + final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( + customFile.getBaseSoftwareModuleName(), customFile.getBaseSoftwareModuleVersion()); + if (customFile.getFileName().equals(name) && currentBaseSoftwareModuleKey.equals(fileSoftwareModuleKey)) { + isDuplicate = true; + break; + } + } + return isDuplicate; + } + + void decreaseNumberOfFileUploadsExpected() { + numberOfFileUploadsExpected.decrementAndGet(); + } + + List getDuplicateFileNamesList() { + return duplicateFileNamesList; + } + + /** + * Update pending action count. + */ + void updateActionCount() { + if (!artifactUploadState.getFileSelected().isEmpty()) { + processBtn.setCaption(SPUILabelDefinitions.PROCESS + "
" + + artifactUploadState.getFileSelected().size() + "
"); + } else { + processBtn.setCaption(SPUILabelDefinitions.PROCESS); + } + } + + void displayValidationMessage() { + // check if streaming of all dropped files are completed + if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) { + displayCompositeMessage(hasDirectory); + } + } + + /** + * Show duplicate file selected message. + * + * @return duplicate file names + */ + public String showDuplicateMessage() { + if (!duplicateFileNamesList.isEmpty()) { + final String fileNames = StringUtils.collectionToCommaDelimitedString(duplicateFileNamesList); + if (duplicateFileNamesList.size() == 1) { + return i18n.get("message.no.duplicateFile") + fileNames; + + } else if (duplicateFileNamesList.size() > 1) { + return i18n.get("message.no.duplicateFiles"); + } + duplicateFileNamesList.clear(); + } + return null; + } + + void increaseNumberOfFileUploadsExpected() { + numberOfFileUploadsExpected.incrementAndGet(); + } + + void updateFileSize(final String name, final long size) { + final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); + final String currentBaseSoftwareModuleKey = HawkbitCommonUtil + .getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); + + for (final CustomFile customFile : artifactUploadState.getFileSelected()) { + final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( + customFile.getBaseSoftwareModuleName(), customFile.getBaseSoftwareModuleVersion()); + if (customFile.getFileName().equals(name) && currentBaseSoftwareModuleKey.equals(fileSoftwareModuleKey)) { + customFile.setFileSize(size); + break; + } + } + } + + void increaseNumberOfFilesActuallyUpload() { + numberOfFilesActuallyUpload.incrementAndGet(); + } + + /** + * Enable process button once upload is completed. + */ + boolean enableProcessBtn() { + if (numberOfFilesActuallyUpload.intValue() >= numberOfFileUploadsExpected.intValue()) { + processBtn.setEnabled(true); + numberOfFileUploadsExpected.set(0); + numberOfFilesActuallyUpload.set(0); + return true; + } + return false; + } + + Set getFileSelected() { + return artifactUploadState.getFileSelected(); + } + + private void discardUploadData(final Button.ClickEvent event) { + if (event.getButton().equals(discardBtn)) { + if (artifactUploadState.getFileSelected().isEmpty()) { + uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); + + } else { + clearFileList(); + } + } + } + + /** + * Clear details. + */ + void clearFileList() { + // delete file system zombies + artifactUploadState.getFileSelected().forEach(customFile -> { + final File file = new File(customFile.getFilePath()); + file.delete(); + }); + + artifactUploadState.getFileSelected().clear(); + artifactUploadState.getBaseSwModuleList().clear(); + processBtn.setCaption(SPUILabelDefinitions.PROCESS); + /* disable when there is no files to upload. */ + processBtn.setEnabled(false); + numberOfFileUploadsExpected.set(0); + numberOfFilesActuallyUpload.set(0); + duplicateFileNamesList.clear(); + } + + private void setConfirmationPopupHeightWidth(final float newWidth, final float newHeight) { + if (currentUploadConfirmationwindow != null) { + currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth(HawkbitCommonUtil + .getArtifactUploadPopupWidth(newWidth, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), + Unit.PIXELS); + currentUploadConfirmationwindow.getUploadDetailsTable().setHeight(HawkbitCommonUtil + .getArtifactUploadPopupHeight(newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), + Unit.PIXELS); + } + } + + /** + * Set artifact upload result pop up size changes. + * + * @param newWidth + * new width of result pop up + * @param newHeight + * new height of result pop up + */ + void setResultPopupHeightWidth(final float newWidth, final float newHeight) { + if (currentUploadConfirmationwindow != null + && currentUploadConfirmationwindow.getCurrentUploadResultWindow() != null) { + final UploadResultWindow uploadResultWindow = currentUploadConfirmationwindow + .getCurrentUploadResultWindow(); + uploadResultWindow.getUploadResultsWindow().setWidth(HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, + SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); + uploadResultWindow.getUploadResultTable().setHeight(HawkbitCommonUtil.getArtifactUploadPopupHeight( + newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); + } + } + + private void displayConfirmWindow(final Button.ClickEvent event) { + if (event.getComponent().getId().equals(SPUIComponetIdProvider.UPLOAD_PROCESS_BUTTON)) { + if (artifactUploadState.getFileSelected().isEmpty()) { + uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); + } else { + currentUploadConfirmationwindow = new UploadConfirmationwindow(this, artifactUploadState); + UI.getCurrent().addWindow(currentUploadConfirmationwindow.getUploadConfrimationWindow()); + setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), + Page.getCurrent().getBrowserWindowHeight()); + } + } + } + + /** + * @return + */ + I18N getI18n() { + return i18n; + } + + /** + * @return + */ + SPInfo getSPInfo() { + return spInfo; + } + + void setCurrentUploadConfirmationwindow(final UploadConfirmationwindow currentUploadConfirmationwindow) { + this.currentUploadConfirmationwindow = currentUploadConfirmationwindow; + } + + /** + * @return + */ + + VerticalLayout getDropAreaLayout() { + return dropAreaLayout; + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadArtifactUIEvent event) { + if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { + ui.access(() -> updateActionCount()); + } + } + + @PreDestroy + void destroy() { + /* + * It's good manners to do this, even though vaadin-spring will + * automatically unsubscribe when this UI is garbage collected. + */ + eventBus.unsubscribe(this); + } + + /** + * set upload status and confirmation window. + * + * @param newWidth + * browser width + * @param newHeight + * browser height + */ + public void setUploadPopupSize(final float newWidth, final float newHeight) { + setConfirmationPopupHeightWidth(newWidth, newHeight); + setResultPopupHeightWidth(newWidth, newHeight); + } + + /** + * @param selectedBaseSoftwareModule + */ + public void refreshArtifactDetailsLayout(final SoftwareModule selectedBaseSoftwareModule) { + eventBus.publish(this, + new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, selectedBaseSoftwareModule)); + } + + /** + * @return the fileUploadLayout + */ + public HorizontalLayout getFileUploadLayout() { + return fileUploadLayout; + } + + public UINotification getUINotification() { + return uiNotification; + } }