diff --git a/hawkbit-ui/pom.xml b/hawkbit-ui/pom.xml index e0bde576a..38b455367 100644 --- a/hawkbit-ui/pom.xml +++ b/hawkbit-ui/pom.xml @@ -254,5 +254,10 @@ allure-junit-adaptor test + + org.scala-lang + scala-library + 2.10.4 + \ No newline at end of file diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java index de8f5867b..8bd33f483 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java @@ -16,5 +16,5 @@ package org.eclipse.hawkbit.ui.artifacts.event; */ public enum UploadArtifactUIEvent { - SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, ENABLE_PROCESS_BUTTON, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISABLE_PROCESS_BUTTON, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE,MINIMIZED_STATUS_POPUP,MAXIMIZED_STATUS_POPUP,UPLOAD_FINISHED,UPLOAD_STARTED, UPLOAD_STREAMINING_FINISHED + SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, ENABLE_PROCESS_BUTTON, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISABLE_PROCESS_BUTTON, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE,MINIMIZED_STATUS_POPUP,MAXIMIZED_STATUS_POPUP, UPLOAD_IN_PROGESS } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java new file mode 100644 index 000000000..776556464 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadFileStatus.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.artifacts.event; + +import java.io.Serializable; + +/** + * + * Holds file and upload status details. + * + */ +public class UploadFileStatus implements Serializable { + + private static final long serialVersionUID = -3599629192216760811L; + + private String fileName; + + private long contentLength; + + private long bytesRead; + + private String failureReason; + + public UploadFileStatus(String fileName){ + this.fileName = fileName; + } + + public UploadFileStatus(String fileName, long bytesRead, long contentLength) { + this.fileName = fileName; + this.contentLength = contentLength; + this.bytesRead = bytesRead; + } + + public UploadFileStatus(String fileName, String failureReason) { + this.failureReason = failureReason; + this.fileName = fileName; + } + + public String getFileName() { + return fileName; + } + + public long getContentLength() { + return contentLength; + } + + public long getBytesRead() { + return bytesRead; + } + + public String getFailureReason() { + return failureReason; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java new file mode 100644 index 000000000..ab10c2e10 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadStatusEvent.java @@ -0,0 +1,34 @@ +package org.eclipse.hawkbit.ui.artifacts.event; +/** + * + * Holds the upload file status. + * + */ +public class UploadStatusEvent { + + public enum UploadStatusEventType { + UPLOAD_FAILED, UPLOAD_IN_PROGRESS, UPLOAD_STARTED, UPLOAD_FINISHED, UPLOAD_SUCCESSFUL, UPLOAD_STREAMING_FAILED, UPLOAD_STREAMING_FINISHED + } + + private UploadStatusEventType uploadProgressEventType; + + private UploadFileStatus uploadStatus; + + public UploadStatusEvent(UploadStatusEventType eventType, UploadFileStatus entity) { + this.uploadProgressEventType = eventType; + this.uploadStatus = entity; + } + + public UploadFileStatus getUploadStatus() { + return uploadStatus; + } + + public void setUploadStatus(UploadFileStatus uploadStatus) { + this.uploadStatus = uploadStatus; + } + + public UploadStatusEventType getUploadProgressEventType() { + return uploadProgressEventType; + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java index ae6a5860e..9c0ade8d1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.ui.artifacts.upload.UploadStatusObject; @@ -68,6 +69,19 @@ public class ArtifactUploadState implements ManagmentEntityState, Serializ private List uploadedFileStatusList = new ArrayList<>(); + private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); + + private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); + + public AtomicInteger getNumberOfFilesActuallyUpload() { + return numberOfFilesActuallyUpload; + } + + public AtomicInteger getNumberOfFileUploadsExpected() { + return numberOfFileUploadsExpected; + } + + public List getUploadedFileStatusList() { return uploadedFileStatusList; } 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 c48dac834..f9d207193 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 @@ -12,9 +12,10 @@ import java.io.IOException; import java.io.OutputStream; import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; -import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; -import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; +import org.eclipse.hawkbit.ui.artifacts.event.UploadFileStatus; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.slf4j.Logger; @@ -59,30 +60,29 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene private final long fileSize; private final UploadLayout view; - private final UploadStatusInfoWindow infoWindow; private final long maxSize; private final Upload upload; private volatile String fileName = null; private volatile String mimeType = null; - private volatile boolean interrupted = false; + private volatile boolean streamingInterrupted = false; + private volatile boolean uploadInterrupted = false; + private String failureReason; private final I18N i18n; private transient EventBus.SessionEventBus eventBus; - UploadHandler(final String fileName, final long fileSize, final UploadLayout view, - final UploadStatusInfoWindow infoWindow, final long maxSize, final Upload upload, final String mimeType) { + final long maxSize, final Upload upload, final String mimeType) { super(); this.fileName = fileName; this.fileSize = fileSize; this.view = view; - this.infoWindow = infoWindow; this.maxSize = maxSize; this.upload = upload; this.mimeType = mimeType; this.i18n = SpringContextHelper.getBean(I18N.class); - this.eventBus = SpringContextHelper.getBean(EventBus.SessionEventBus.class); + this.eventBus = SpringContextHelper.getBean(EventBus.SessionEventBus.class); } /** @@ -97,7 +97,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene } catch (final ArtifactUploadFailedException e) { LOG.error("Atifact upload failed {} ", e); failureReason = e.getMessage(); - interrupted = true; + streamingInterrupted = true; return new NullOutputStream(); } } @@ -112,7 +112,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene public OutputStream receiveUpload(final String fileName, final String mimeType) { this.fileName = fileName; this.mimeType = mimeType; - //reset has directory flag before upload + // reset has directory flag before upload view.setHasDirectory(false); try { if (view.checkIfSoftwareModuleIsSelected()) { @@ -127,6 +127,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene LOG.error("Atifact upload failed {} ", e); failureReason = e.getMessage(); upload.interruptUpload(); + uploadInterrupted = true; } // if final validation fails ,final no upload ,return NullOutputStream return new NullOutputStream(); @@ -141,13 +142,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void uploadSucceeded(final SucceededEvent event) { LOG.debug("Streaming finished for file :{}", event.getFilename()); - view.updateFileSize(event.getFilename(), event.getLength()); - - // recorded that we now one more uploaded - view.increaseNumberOfFilesActuallyUpload(); - - // inform upload status window - infoWindow.uploadSucceeded(event.getFilename()); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_SUCCESSFUL, new UploadFileStatus( + event.getFilename(), 0, event.getLength()))); } /** @@ -160,20 +156,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void streamingFinished(final StreamingEndEvent event) { LOG.debug("Streaming finished for file :{}", event.getFileName()); - // record that we now one more uploaded - view.increaseNumberOfFilesActuallyUpload(); - - // inform upload status window - infoWindow.uploadSucceeded(event.getFileName()); - - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); - } - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_STREAMINING_FINISHED); - - // display the duplicate message after streaming all files - view.displayDuplicateValidationMessage(); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FINISHED, + new UploadFileStatus(event.getFileName(), 0, event.getContentLength()))); } /** @@ -185,12 +169,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void uploadFinished(final FinishedEvent event) { LOG.debug("Upload finished for file :{}", event.getFilename()); - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); - } - view.updateActionCount(); - + eventBus.publish(this, + new UploadStatusEvent(UploadStatusEventType.UPLOAD_FINISHED, new UploadFileStatus(event.getFilename()))); } /** @@ -201,7 +181,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void streamingStarted(final StreamingStartEvent event) { LOG.debug("Streaming started for file :{}", fileName); - infoWindow.uploadStarted(fileName); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED, new UploadFileStatus( + fileName, 0, 0))); } /** @@ -213,12 +194,14 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene public void uploadStarted(final StartedEvent event) { // single file session if (view.isSoftwareModuleSelected() && !view.checkIfFileIsDuplicate(event.getFilename())) { - infoWindow.uploadSessionStarted(); LOG.debug("Upload started for file :{}", event.getFilename()); - infoWindow.uploadStarted(event.getFilename()); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED, new UploadFileStatus( + event.getFilename(), 0, 0))); } else { failureReason = i18n.get("message.upload.failed"); upload.interruptUpload(); + // actual interrupt will happen a bit late so setting the below flag + uploadInterrupted = true; } } @@ -239,23 +222,21 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public void updateProgress(final long readBytes, final long contentLength) { - if (readBytes > maxSize || contentLength > maxSize) { - LOG.error("User tried to upload more than was allowed ({}).", maxSize); - - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - view.updateActionCount(); - - failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); - infoWindow.uploadFailed(fileName, failureReason); - upload.interruptUpload(); - interrupted = true; - return; + //Update progress is called event after upload interrupted in uploadStarted method + if (!uploadInterrupted) { + if (readBytes > maxSize || contentLength > maxSize) { + LOG.error("User tried to upload more than was allowed ({}).", maxSize); + failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_FAILED, new UploadFileStatus( + fileName, failureReason))); + upload.interruptUpload(); + uploadInterrupted = true; + return; + } + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS, + new UploadFileStatus(fileName, readBytes, contentLength))); + LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength); } - - infoWindow.updateProgress(fileName, readBytes, contentLength); - LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength); } /** @@ -267,19 +248,14 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene public void onProgress(final StreamingProgressEvent event) { if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) { LOG.error("User tried to upload more than was allowed ({}).", maxSize); - - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_STREAMINING_FINISHED); - failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); - infoWindow.uploadFailed(event.getFileName(), failureReason); - interrupted = true; + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_FAILED, new UploadFileStatus( + fileName, failureReason))); + streamingInterrupted = true; return; } - - infoWindow.updateProgress(event.getFileName(), event.getBytesReceived(), event.getContentLength()); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS, new UploadFileStatus( + fileName, event.getBytesReceived(), event.getContentLength()))); // Logging to solve sonar issue LOG.trace("Streaming in progress for file :{}", event.getFileName()); } @@ -293,29 +269,15 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void streamingFailed(final StreamingErrorEvent event) { LOG.info("Streaming failed for file :{}", event.getFileName()); - - view.decreaseNumberOfFileUploadsExpected(); - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_STREAMINING_FINISHED); - - if (failureReason != null) { - // Display custom error message - infoWindow.uploadFailed(event.getFileName(), failureReason); - } else { - // internal upload error - infoWindow.uploadFailed(event.getFileName(), event.getException().getMessage()); + if (failureReason == null) { + failureReason = event.getException().getMessage(); } - // check if we are finished - if (view.enableProcessBtn()) { - infoWindow.uploadSessionFinished(); - } - view.displayDuplicateValidationMessage(); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FAILED, + new UploadFileStatus(fileName, failureReason))); LOG.info("Streaming failed due to :{}", event.getException()); } - /** * Upload failed for {@link Upload} variant. * @@ -324,23 +286,13 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene @Override public void uploadFailed(final FailedEvent event) { LOG.info("Upload failed for file :{}", event.getFilename()); - view.decreaseNumberOfFileUploadsExpected(); - /** - * If upload interrupted because of duplicate file,do not remove the - * file already in upload list - **/ - if (!view.getDuplicateFileNamesList().isEmpty()) { - final SoftwareModule sw = view.getSoftwareModuleSelected(); - view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); - } - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_STREAMINING_FINISHED); - if (failureReason != null) { - infoWindow.uploadFailed(event.getFilename(), failureReason); - } else { - infoWindow.uploadFailed(event.getFilename(), event.getReason().getMessage()); + if (failureReason == null) { + failureReason = event.getReason().getMessage(); } + System.out.println("failureReason:::"+failureReason); + eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_FAILED, new UploadFileStatus( + fileName, failureReason))); LOG.info("Upload failed for file :{}", event.getReason()); - } /** @@ -348,7 +300,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene */ @Override public boolean isInterrupted() { - return interrupted; + return streamingInterrupted; } private static class NullOutputStream extends OutputStream { 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 9e304efe8..58661773d 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 @@ -16,7 +16,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -26,6 +25,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; @@ -97,13 +98,9 @@ public class UploadLayout extends VerticalLayout { @Autowired private transient SPInfo spInfo; - private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); - - private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); - private final List duplicateFileNamesList = new ArrayList<>(); - private Button processBtn ; + private Button processBtn; private Button discardBtn; @@ -128,11 +125,48 @@ public class UploadLayout extends VerticalLayout { void init() { createComponents(); buildLayout(); - updateActionCount(); restoreState(); eventBus.subscribe(this); ui = UI.getCurrent(); } + + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadArtifactUIEvent event) { + if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { + ui.access(() -> updateActionCount()); + } else if (event == UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP) { + ui.access(() -> showUploadStatusButton()); + } else if (event == UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP) { + ui.access(() -> maximizeStatusPopup()); + } + } + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadStatusEvent event) { + if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) { + ui.access(() -> setUploadStatusButtonIconToInProgress()); + } + else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FAILED) { + ui.access(() -> onUploadFailure(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FINISHED) { + ui.access(() -> onUploadCompletion()); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) { + ui.access(() -> onUploadSuccess(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) { + ui.access(() -> onUploadStreamingFailure(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) { + ui.access(() -> onUploadStreamingSuccess(event)); + } + } + + @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); + } private void createComponents() { createUploadStatusButton(); @@ -143,8 +177,8 @@ public class UploadLayout extends VerticalLayout { private void buildLayout() { final Upload upload = new Upload(); - final UploadHandler uploadHandler = new UploadHandler(null, 0, this, uploadInfoWindow, - spInfo.getMaxArtifactFileSize(), upload, null); + final UploadHandler uploadHandler = new UploadHandler(null, 0, this, spInfo.getMaxArtifactFileSize(), upload, + null); upload.setButtonCaption(i18n.get("upload.file")); upload.setImmediate(true); upload.setReceiver(uploadHandler); @@ -176,9 +210,15 @@ public class UploadLayout extends VerticalLayout { } private void restoreState() { + updateActionCount(); + if (!artifactUploadState.getFileSelected().isEmpty() && artifactUploadState.isUploadCompleted()) { + processBtn.setEnabled(true); + } if (artifactUploadState.isStatusPopupMinimized()) { showUploadStatusButton(); - setUploadStatusButtonIconToFinished(); + if (artifactUploadState.isUploadCompleted()) { + setUploadStatusButtonIconToFinished(); + } } } @@ -204,10 +244,10 @@ public class UploadLayout extends VerticalLayout { for (final Html5File file : files) { processFile(file); } - if (numberOfFileUploadsExpected.get() > 0) { + if (artifactUploadState.getNumberOfFileUploadsExpected().get() > 0) { processBtn.setEnabled(false); // reset before we start - uploadInfoWindow.uploadSessionStarted(); + // uploadInfoWindow.uploadSessionStarted(); } else { // If the upload is not started, it signifies all // dropped files as either duplicate or directory.So @@ -220,7 +260,7 @@ public class UploadLayout extends VerticalLayout { private void processFile(final Html5File file) { if (!isDirectory(file)) { if (!checkForDuplicate(file.getFileName())) { - numberOfFileUploadsExpected.incrementAndGet(); + artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet(); file.setStreamVariable(createStreamVariable(file)); } } else { @@ -229,7 +269,7 @@ public class UploadLayout extends VerticalLayout { } private StreamVariable createStreamVariable(final Html5File file) { - return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this, uploadInfoWindow, + return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this, spInfo.getMaxArtifactFileSize(), null, file.getType()); } @@ -282,9 +322,7 @@ public class UploadLayout extends VerticalLayout { processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); processBtn.addClickListener(event -> displayConfirmWindow(event)); processBtn.setHtmlContentAllowed(true); - if (artifactUploadState.getFileSelected().isEmpty()) { - processBtn.setEnabled(false); - } + processBtn.setEnabled(false); } private void createDiscardBtn() { @@ -349,13 +387,15 @@ public class UploadLayout extends VerticalLayout { artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSoftwareModule); } return out; - } catch (final FileNotFoundException e) { + } + 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(final DragAndDropEvent event) { @@ -430,7 +470,7 @@ public class UploadLayout extends VerticalLayout { } void decreaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.decrementAndGet(); + artifactUploadState.getNumberOfFileUploadsExpected().decrementAndGet(); } List getDuplicateFileNamesList() { @@ -451,7 +491,7 @@ public class UploadLayout extends VerticalLayout { void displayDuplicateValidationMessage() { // check if streaming of all dropped files are completed - if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) { + if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() == artifactUploadState.getNumberOfFileUploadsExpected().intValue()) { displayCompositeMessage(); } } @@ -466,7 +506,6 @@ public class UploadLayout extends VerticalLayout { } else if (duplicateFileNamesList.size() > 1) { message.append(i18n.get("message.no.duplicateFiles")); } - duplicateFileNamesList.clear(); } return message.toString(); } @@ -476,7 +515,7 @@ public class UploadLayout extends VerticalLayout { } void increaseNumberOfFileUploadsExpected() { - numberOfFileUploadsExpected.incrementAndGet(); + artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet(); } void updateFileSize(final String name, final long size) { @@ -495,17 +534,19 @@ public class UploadLayout extends VerticalLayout { } void increaseNumberOfFilesActuallyUpload() { - numberOfFilesActuallyUpload.incrementAndGet(); + artifactUploadState.getNumberOfFilesActuallyUpload().incrementAndGet(); } /** * Enable process button once upload is completed. */ boolean enableProcessBtn() { - if (numberOfFilesActuallyUpload.intValue() >= numberOfFileUploadsExpected.intValue()) { + if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() >= artifactUploadState + .getNumberOfFileUploadsExpected().intValue() + && artifactUploadState.getNumberOfFilesActuallyUpload().get() != 0) { processBtn.setEnabled(true); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); + artifactUploadState.getNumberOfFilesActuallyUpload().set(0); + artifactUploadState.getNumberOfFileUploadsExpected().set(0); return true; } return false; @@ -546,8 +587,8 @@ public class UploadLayout extends VerticalLayout { processBtn.setCaption(SPUILabelDefinitions.PROCESS); /* disable when there is no files to upload. */ processBtn.setEnabled(false); - numberOfFileUploadsExpected.set(0); - numberOfFilesActuallyUpload.set(0); + artifactUploadState.getNumberOfFilesActuallyUpload().set(0); + artifactUploadState.getNumberOfFileUploadsExpected().set(0); duplicateFileNamesList.clear(); } @@ -623,33 +664,70 @@ public class UploadLayout extends VerticalLayout { return dropAreaLayout; } - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final UploadArtifactUIEvent event) { - if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { - ui.access(() -> updateActionCount()); - } else if (event == UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP) { - ui.access(() -> showUploadStatusButton()); - } else if (event == UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP) { - ui.access(() -> maximizeStatusPopup()); - } else if (event == UploadArtifactUIEvent.UPLOAD_FINISHED) { - ui.access(() -> setUploadStatusButtonIconToFinished()); - } else if (event == UploadArtifactUIEvent.UPLOAD_STARTED) { - ui.access(() -> setUploadStatusButtonIconToInProgress()); - }else if (event == UploadArtifactUIEvent.UPLOAD_STREAMINING_FINISHED) { - //TODO re-check - updateActionCount(); - enableProcessBtn(); - } + private void onUploadStreamingSuccess(UploadStatusEvent event) { + increaseNumberOfFilesActuallyUpload(); + updateActionCount(); + enableProcessBtn(); + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + } + // display the duplicate message after streaming all files + displayDuplicateValidationMessage(); + duplicateFileNamesList.clear(); } - @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); + private void onUploadStreamingFailure(UploadStatusEvent event) { + onUploadFailure(event); + updateActionCount(); + enableProcessBtn(); + // check if we are finished + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + } + displayDuplicateValidationMessage(); + } + + private void onUploadSuccess(UploadStatusEvent event) { + updateFileSize(event.getUploadStatus().getFileName(), event.getUploadStatus().getContentLength()); + // recorded that we now one more uploaded + increaseNumberOfFilesActuallyUpload(); + } + + private void onUploadCompletion() { + // check if we are finished + if (isUploadComplete()) { + uploadInfoWindow.uploadSessionFinished(); + setUploadStatusButtonIconToFinished(); + } + updateActionCount(); + enableProcessBtn(); + duplicateFileNamesList.clear(); + } + + private boolean isUploadComplete() { + int uploadedCount = artifactUploadState.getNumberOfFilesActuallyUpload().intValue(); + int expectedUploadsCount = artifactUploadState.getNumberOfFileUploadsExpected().intValue(); + return uploadedCount == expectedUploadsCount; + } + + private void onUploadFailure(final UploadStatusEvent event) { + decreaseNumberOfFileUploadsExpected(); + /** + * If upload interrupted because of duplicate file,do not remove the + * file already in upload list + **/ + if (getDuplicateFileNamesList().isEmpty() + || !getDuplicateFileNamesList().contains(event.getUploadStatus().getFileName())) { + final SoftwareModule sw = getSoftwareModuleSelected(); + getFileSelected().remove( + new CustomFile(event.getUploadStatus().getFileName(), sw.getName(), sw.getVersion())); + //failed reason to be updated only if there is error other than duplicate file error + uploadInfoWindow.uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getFailureReason()); + } } /** @@ -738,4 +816,5 @@ public class UploadLayout extends VerticalLayout { uploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE); uploadStatusButton.setIcon(null); } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java index 4693ab3dc..2efd929d3 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusInfoWindow.java @@ -11,7 +11,12 @@ package org.eclipse.hawkbit.ui.artifacts.upload; import java.util.List; import java.util.stream.Collectors; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent; +import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType; import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; @@ -19,6 +24,8 @@ import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.springframework.beans.factory.annotation.Autowired; import org.vaadin.spring.events.EventBus; +import org.vaadin.spring.events.EventScope; +import org.vaadin.spring.events.annotation.EventBusListenerMethod; import com.vaadin.data.Container.Indexed; import com.vaadin.data.Item; @@ -69,9 +76,9 @@ public class UploadStatusInfoWindow extends Window { private static final long serialVersionUID = 1L; - private final Grid grid; + private Grid grid; - private final IndexedContainer uploads; + private IndexedContainer uploads; private volatile boolean errorOccured = false; @@ -84,12 +91,15 @@ public class UploadStatusInfoWindow extends Window { private Button closeButton; private Button resizeButton; + + private UI ui; + /** * Default Constructor. */ - UploadStatusInfoWindow() { - super(); + @PostConstruct + void init() { setPopupProperties(); createStatusPopupHeaderComponents(); @@ -106,8 +116,45 @@ public class UploadStatusInfoWindow extends Window { mainLayout.addComponents(getCaptionLayout(), grid); mainLayout.setExpandRatio(grid, 1.0F); setContent(mainLayout); + eventBus.subscribe(this); + ui = UI.getCurrent(); + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvent(final UploadStatusEvent event) { + if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_IN_PROGRESS) { + UI.getCurrent().access( + () -> updateProgress(event.getUploadStatus().getFileName(), event.getUploadStatus().getBytesRead(), + event.getUploadStatus().getContentLength())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) { + UI.getCurrent().access(() -> onStartOfUpload(event)); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) { + ui.access(() -> uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus() + .getFailureReason())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) { + UI.getCurrent().access(() -> uploadSucceeded(event.getUploadStatus().getFileName())); + } else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) { + ui.access(() -> uploadSucceeded(event.getUploadStatus().getFileName())); + } + } + + private void onStartOfUpload(UploadStatusEvent event) { + uploadSessionStarted(); + uploadStarted(event.getUploadStatus().getFileName()); + } + + + @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); + } + private void restoreState() { Indexed container = grid.getContainerDataSource(); if (container.getItemIds().isEmpty()) { @@ -119,8 +166,10 @@ public class UploadStatusInfoWindow extends Window { item.getItemProperty(PROGRESS).setValue(statusObject.getProgress()); item.getItemProperty(FILE_NAME).setValue(statusObject.getFilename()); } - artifactUploadState.setUploadCompleted(true); - minimizeButton.setEnabled(false); + // artifactUploadState.setUploadCompleted(true); + if (artifactUploadState.isUploadCompleted()) { + minimizeButton.setEnabled(false); + } } } @@ -130,6 +179,7 @@ public class UploadStatusInfoWindow extends Window { setResizable(false); setDraggable(true); setClosable(false); + setModal(true); } private void setGridColumnProperties() { @@ -192,6 +242,8 @@ public class UploadStatusInfoWindow extends Window { private static class StatusRenderer extends HtmlRenderer { + private static final long serialVersionUID = -5365795450234970943L; + @Override public JsonValue encode(final String value) { String result ; @@ -216,18 +268,17 @@ public class UploadStatusInfoWindow extends Window { void uploadSessionFinished() { if (!errorOccured) { close(); - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_FINISHED); - artifactUploadState.setUploadCompleted(true); - minimizeButton.setEnabled(false); } - + artifactUploadState.setUploadCompleted(true); + minimizeButton.setEnabled(false); } void uploadSessionStarted() { - close(); - openWindow(); + if (!artifactUploadState.isStatusPopupMinimized()) { + close(); + openWindow(); + } minimizeButton.setEnabled(true); - eventBus.publish(this, UploadArtifactUIEvent.UPLOAD_STARTED); artifactUploadState.setUploadCompleted(false); } @@ -287,22 +338,22 @@ public class UploadStatusInfoWindow extends Window { } void uploadFailed(final String filename, final String errorReason) { + if (!errorOccured) { + errorOccured = true; + } + String status = "Failed"; final Item item = uploads.getItem(filename); if (item != null) { - if (!errorOccured) { - errorOccured = true; - } item.getItemProperty(REASON).setValue(errorReason); - String status = "Failed"; item.getItemProperty(STATUS).setValue(status); - List uploadStatusObjectList = (List) artifactUploadState - .getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename)) - .collect(Collectors.toList()); - if (!uploadStatusObjectList.isEmpty()) { - UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0); - uploadStatusObject.setStatus(status); - uploadStatusObject.setReason(errorReason); - } + } + List uploadStatusObjectList = (List) artifactUploadState + .getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename)) + .collect(Collectors.toList()); + if (!uploadStatusObjectList.isEmpty()) { + UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0); + uploadStatusObject.setStatus(status); + uploadStatusObject.setReason(errorReason); } } @@ -370,4 +421,5 @@ public class UploadStatusInfoWindow extends Window { closeBtn.addClickListener(event -> clearWindow()); return closeBtn; } + }