Feature do not temp store uploaded files (#763)
* Upload artefacts directly without creating a temp file * Remove redundant code that checks if user tries to update a directory * Handle UI upload exceptions, use Spring thread pool * Clean up code * Fix review findings * Fix Sonar findings Signed-off-by: Stefan Klotz <stefan.klotz@bosch-si.com> Signed-off-by: Stefan Behl <stefan.behl@bosch-si.com>
This commit is contained in:
committed by
Stefan Behl
parent
49d064df18
commit
d4c1e82090
@@ -25,9 +25,7 @@ public class TargetWithActionType {
|
|||||||
private String maintenanceWindowTimeZone;
|
private String maintenanceWindowTimeZone;
|
||||||
|
|
||||||
public TargetWithActionType(final String controllerId) {
|
public TargetWithActionType(final String controllerId) {
|
||||||
this.controllerId = controllerId;
|
this(controllerId, ActionType.FORCED, 0);
|
||||||
this.actionType = ActionType.FORCED;
|
|
||||||
this.forceTime = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime) {
|
public TargetWithActionType(final String controllerId, final ActionType actionType, final long forceTime) {
|
||||||
@@ -115,4 +113,13 @@ public class TargetWithActionType {
|
|||||||
public String getMaintenanceWindowTimeZone() {
|
public String getMaintenanceWindowTimeZone() {
|
||||||
return maintenanceWindowTimeZone;
|
return maintenanceWindowTimeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TargetWithActionType [controllerId=" + controllerId + ", actionType=" + getActionType() + ", forceTime="
|
||||||
|
+ getForceTime() + ", maintenanceSchedule=" + getMaintenanceSchedule() + ", maintenanceWindowDuration="
|
||||||
|
+ getMaintenanceWindowDuration() + ", maintenanceWindowTimeZone=" + getMaintenanceWindowTimeZone()
|
||||||
|
+ "]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ public abstract class AbstractDsAssignmentStrategy {
|
|||||||
.publishEvent(new CancelTargetAssignmentEvent(target, actionId, applicationContext.getId())));
|
.publishEvent(new CancelTargetAssignmentEvent(target, actionId, applicationContext.getId())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("squid:S2259")
|
||||||
JpaAction createTargetAction(final Map<String, TargetWithActionType> targetsWithActionMap, final JpaTarget target,
|
JpaAction createTargetAction(final Map<String, TargetWithActionType> targetsWithActionMap, final JpaTarget target,
|
||||||
final JpaDistributionSet set) {
|
final JpaDistributionSet set) {
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
@@ -100,6 +103,7 @@ import com.google.common.collect.Lists;
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@Validated
|
@Validated
|
||||||
public class JpaDeploymentManagement implements DeploymentManagement {
|
public class JpaDeploymentManagement implements DeploymentManagement {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class);
|
private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -321,8 +325,10 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
assignmentStrategy.updateTargetStatus(set, targetIds, currentUser);
|
assignmentStrategy.updateTargetStatus(set, targetIds, currentUser);
|
||||||
|
|
||||||
final Map<String, JpaAction> targetIdsToActions = targets.stream()
|
final Map<String, JpaAction> targetIdsToActions = targets.stream()
|
||||||
.map(t -> actionRepository.save(assignmentStrategy.createTargetAction(targetsWithActionMap, t, set)))
|
.map(trg -> createTargetAction(assignmentStrategy, targetsWithActionType, controllerIDs, targets,
|
||||||
.collect(Collectors.toMap(a -> a.getTarget().getControllerId(), Function.identity()));
|
targetsWithActionMap, trg, set))
|
||||||
|
.map(actionRepository::save)
|
||||||
|
.collect(Collectors.toMap(action -> action.getTarget().getControllerId(), Function.identity()));
|
||||||
|
|
||||||
// create initial action status when action is created so we remember
|
// create initial action status when action is created so we remember
|
||||||
// the initial running status because we will change the status
|
// the initial running status because we will change the status
|
||||||
@@ -578,7 +584,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
@Override
|
@Override
|
||||||
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||||
|
|
||||||
return actionRepository.findByActiveAndTarget(pageable, controllerId, true);
|
return actionRepository.findByActiveAndTarget(pageable, controllerId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,14 +597,12 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
@Override
|
@Override
|
||||||
public long countActionsByTarget(final String controllerId) {
|
public long countActionsByTarget(final String controllerId) {
|
||||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||||
|
|
||||||
return actionRepository.countByTargetControllerId(controllerId);
|
return actionRepository.countByTargetControllerId(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long countActionsByTarget(final String rsqlParam, final String controllerId) {
|
public long countActionsByTarget(final String rsqlParam, final String controllerId) {
|
||||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||||
|
|
||||||
return actionRepository.count(createSpecificationFor(controllerId, rsqlParam));
|
return actionRepository.count(createSpecificationFor(controllerId, rsqlParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,7 +687,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
@Override
|
@Override
|
||||||
public Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long dsId) {
|
public Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long dsId) {
|
||||||
throwExceptionIfDistributionSetDoesNotExist(dsId);
|
throwExceptionIfDistributionSetDoesNotExist(dsId);
|
||||||
|
|
||||||
return actionRepository.findByDistributionSetId(pageable, dsId);
|
return actionRepository.findByDistributionSetId(pageable, dsId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,14 +698,12 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
@Override
|
@Override
|
||||||
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
||||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||||
|
|
||||||
return distributionSetRepository.findAssignedToTarget(controllerId);
|
return distributionSetRepository.findAssignedToTarget(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
||||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||||
|
|
||||||
return distributionSetRepository.findInstalledAtTarget(controllerId);
|
return distributionSetRepository.findInstalledAtTarget(controllerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +736,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
return deleteQuery.executeUpdate();
|
return deleteQuery.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(Database database) {
|
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(final Database database) {
|
||||||
return QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.getOrDefault(database,
|
return QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED.getOrDefault(database,
|
||||||
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED_DEFAULT);
|
QUERY_DELETE_ACTIONS_BY_STATE_AND_LAST_MODIFIED_DEFAULT);
|
||||||
}
|
}
|
||||||
@@ -749,4 +749,52 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
|||||||
return "#" + Joiner.on(",#").join(elements);
|
return "#" + Joiner.on(",#").join(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "squid:S1695", "squid:S1696" })
|
||||||
|
private JpaAction createTargetAction(final AbstractDsAssignmentStrategy assignmentStrategy,
|
||||||
|
final Collection<TargetWithActionType> targetsWithActionType, final List<String> controllerIDs,
|
||||||
|
final List<JpaTarget> targets, final Map<String, TargetWithActionType> targetsWithActionMap,
|
||||||
|
final JpaTarget target, final JpaDistributionSet set) {
|
||||||
|
try {
|
||||||
|
return assignmentStrategy.createTargetAction(targetsWithActionMap, target, set);
|
||||||
|
} catch (final NullPointerException e) {
|
||||||
|
dumpDistributionSetAssignment(target, set, targetsWithActionType, controllerIDs, targets,
|
||||||
|
targetsWithActionMap);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dumpDistributionSetAssignment(final JpaTarget target, final JpaDistributionSet set,
|
||||||
|
final Collection<TargetWithActionType> targetsWithActionType, final List<String> controllerIDs,
|
||||||
|
final List<JpaTarget> targets, final Map<String, TargetWithActionType> targetsWithActionMap) {
|
||||||
|
final ObjectWriter writer = new ObjectMapper().writer();
|
||||||
|
final String correlationID = "DistributionSetAssignmentDump[" + Thread.currentThread().getId() + "]";
|
||||||
|
dump(correlationID, "Target", Objects.toString(target));
|
||||||
|
dump(correlationID, "DistributionSet", Objects.toString(set));
|
||||||
|
if (target != null) {
|
||||||
|
dump(correlationID, "ControllerID", Objects.toString(target.getControllerId()));
|
||||||
|
if (set != null) {
|
||||||
|
dump(correlationID, "Actions", toString(writer,
|
||||||
|
actionRepository.findByTargetAndDistributionSet(new PageRequest(0, 500), target, set)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dump(correlationID, "ControllerIDs", toString(writer, controllerIDs));
|
||||||
|
dump(correlationID, "Targets", toString(writer, targets));
|
||||||
|
dump(correlationID, "TargetsWithActionType", toString(writer, targetsWithActionType));
|
||||||
|
dump(correlationID, "TargetsWithActionMap", toString(writer, targetsWithActionMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dump(final String prefix, final String key, final String value) {
|
||||||
|
LOG.error("{} >>> {}: {}", prefix, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("squid:S1166")
|
||||||
|
private static String toString(final ObjectWriter writer, final Object o) {
|
||||||
|
try {
|
||||||
|
return writer.writeValueAsString(o);
|
||||||
|
} catch (final JsonProcessingException e) {
|
||||||
|
LOG.error("Object serialization failed", e);
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,8 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
|
return "JpaAction [distributionSet=" + distributionSet.getId() + ", version=" + getOptLockRevision() + ", id="
|
||||||
+ getId() + "]";
|
+ getId() + ", actionType=" + getActionType() + ", isActive=" + isActive() + ", createdAt="
|
||||||
|
+ getCreatedAt() + ", lastModifiedAt=" + getLastModifiedAt() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
@@ -27,13 +27,14 @@ import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModule
|
|||||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
|
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
|
||||||
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
|
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
|
||||||
|
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.vaadin.spring.events.EventBus;
|
import org.vaadin.spring.events.EventBus;
|
||||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||||
|
|
||||||
import com.google.common.io.ByteStreams;
|
import com.vaadin.ui.UI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for transferring files from the browser to the
|
* Abstract base class for transferring files from the browser to the
|
||||||
@@ -49,8 +50,6 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
|
|
||||||
private volatile boolean uploadInterrupted;
|
private volatile boolean uploadInterrupted;
|
||||||
|
|
||||||
private volatile String tempFilePath;
|
|
||||||
|
|
||||||
private volatile String failureReason;
|
private volatile String failureReason;
|
||||||
|
|
||||||
private final ArtifactUploadState artifactUploadState;
|
private final ArtifactUploadState artifactUploadState;
|
||||||
@@ -61,11 +60,14 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
|
|
||||||
private final VaadinMessageSource i18n;
|
private final VaadinMessageSource i18n;
|
||||||
|
|
||||||
|
protected final UINotification uiNotification;
|
||||||
|
|
||||||
AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n) {
|
AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n) {
|
||||||
this.artifactManagement = artifactManagement;
|
this.artifactManagement = artifactManagement;
|
||||||
this.i18n = i18n;
|
this.i18n = i18n;
|
||||||
this.eventBus = SpringContextHelper.getBean(EventBus.UIEventBus.class);
|
this.eventBus = SpringContextHelper.getBean(EventBus.UIEventBus.class);
|
||||||
this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class);
|
this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class);
|
||||||
|
this.uiNotification = SpringContextHelper.getBean(UINotification.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isDuplicateFile() {
|
protected boolean isDuplicateFile() {
|
||||||
@@ -99,6 +101,13 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
return i18n;
|
return i18n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId,
|
||||||
|
final String mimeType) {
|
||||||
|
SpringContextHelper.getBean("asyncExecutor", ExecutorService.class)
|
||||||
|
.execute(
|
||||||
|
new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent()));
|
||||||
|
}
|
||||||
|
|
||||||
private void setFailureReason(final String failureReason) {
|
private void setFailureReason(final String failureReason) {
|
||||||
this.failureReason = failureReason;
|
this.failureReason = failureReason;
|
||||||
}
|
}
|
||||||
@@ -131,22 +140,13 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void publishUploadProgressEvent(final FileUploadId fileUploadId, final long bytesReceived,
|
protected void publishUploadProgressEvent(final FileUploadId fileUploadId, final long bytesReceived,
|
||||||
final long fileSize, final String tempFilePath) {
|
final long fileSize) {
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
LOG.trace("Upload in progress for file {} - {}%", fileUploadId,
|
LOG.trace("Upload in progress for file {} - {}%", fileUploadId,
|
||||||
String.format("%.0f", (double) bytesReceived / (double) fileSize * 100));
|
String.format("%.0f", (double) bytesReceived / (double) fileSize * 100));
|
||||||
}
|
}
|
||||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||||
FileUploadStatus.UPLOAD_IN_PROGRESS, bytesReceived, fileSize, tempFilePath);
|
FileUploadStatus.UPLOAD_IN_PROGRESS, bytesReceived, fileSize);
|
||||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
|
||||||
eventBus.publish(this, fileUploadProgress);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publishUploadSucceeded(final FileUploadId fileUploadId, final long fileSize,
|
|
||||||
final String tempFilePath) {
|
|
||||||
LOG.info("Upload succeeded for file {}", fileUploadId);
|
|
||||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
|
||||||
FileUploadStatus.UPLOAD_SUCCESSFUL, fileSize, fileSize, tempFilePath);
|
|
||||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||||
eventBus.publish(this, fileUploadProgress);
|
eventBus.publish(this, fileUploadProgress);
|
||||||
}
|
}
|
||||||
@@ -158,6 +158,19 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
eventBus.publish(this, fileUploadProgress);
|
eventBus.publish(this, fileUploadProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void publishUploadSucceeded(final FileUploadId fileUploadId, final long fileSize) {
|
||||||
|
LOG.info("Upload succeeded for file {}", fileUploadId);
|
||||||
|
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||||
|
FileUploadStatus.UPLOAD_SUCCESSFUL, fileSize, fileSize);
|
||||||
|
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||||
|
eventBus.publish(this, fileUploadProgress);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void publishArtifactsChanged(final FileUploadId fileUploadId) {
|
||||||
|
eventBus.publish(this,
|
||||||
|
new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, fileUploadId.getSoftwareModuleId()));
|
||||||
|
}
|
||||||
|
|
||||||
protected void publishUploadFailedEvent(final FileUploadId fileUploadId, final String failureReason,
|
protected void publishUploadFailedEvent(final FileUploadId fileUploadId, final String failureReason,
|
||||||
final Exception uploadException) {
|
final Exception uploadException) {
|
||||||
LOG.info("Upload failed for file {} due to {}", fileUploadId,
|
LOG.info("Upload failed for file {} due to {}", fileUploadId,
|
||||||
@@ -180,59 +193,94 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OutputStream createOutputStreamForTempFile() throws IOException {
|
protected static void tryToCloseIOStream(final OutputStream outputStream) {
|
||||||
|
if (outputStream != null) {
|
||||||
if (isUploadInterrupted()) {
|
try {
|
||||||
return ByteStreams.nullOutputStream();
|
outputStream.close();
|
||||||
}
|
} catch (final IOException e1) {
|
||||||
|
LOG.error("Closing output stream caused an exception {}", e1);
|
||||||
final File tempFile = File.createTempFile("spUiArtifactUpload", null);
|
|
||||||
|
|
||||||
// we return the outputstream so we cannot close it here
|
|
||||||
@SuppressWarnings("squid:S2095")
|
|
||||||
final OutputStream out = new FileOutputStream(tempFile);
|
|
||||||
|
|
||||||
tempFilePath = tempFile.getAbsolutePath();
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getTempFilePath() {
|
|
||||||
return tempFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exception squid:S3655 - Optional access is checked in
|
|
||||||
// checkIfArtifactDetailsDispalyed subroutine
|
|
||||||
@SuppressWarnings("squid:S3655")
|
|
||||||
protected void transferArtifactToRepository(final FileUploadId fileUploadId, final long fileSize,
|
|
||||||
final String mimeType, final String tempFilePath) {
|
|
||||||
|
|
||||||
final File newFile = new File(tempFilePath);
|
|
||||||
|
|
||||||
final String filename = fileUploadId.getFilename();
|
|
||||||
LOG.info("Transfering tempfile {} - {} to repository", filename, tempFilePath);
|
|
||||||
try (FileInputStream fis = new FileInputStream(newFile)) {
|
|
||||||
|
|
||||||
artifactManagement.create(fis, fileUploadId.getSoftwareModuleId(), filename, null, null, true, mimeType,
|
|
||||||
fileSize);
|
|
||||||
|
|
||||||
publishUploadSucceeded(fileUploadId, fileSize, tempFilePath);
|
|
||||||
|
|
||||||
eventBus.publish(this, new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED,
|
|
||||||
fileUploadId.getSoftwareModuleId()));
|
|
||||||
|
|
||||||
} catch (final ArtifactUploadFailedException | InvalidSHA1HashException | InvalidMD5HashException
|
|
||||||
| IOException e) {
|
|
||||||
publishUploadFailedEvent(fileUploadId, i18n.getMessage("message.upload.failed"), e);
|
|
||||||
LOG.error("Failed to transfer file to repository", e);
|
|
||||||
} finally {
|
|
||||||
LOG.debug("Deleting tempfile {} - {}", filename, newFile.getAbsolutePath());
|
|
||||||
if (newFile.exists() && !newFile.delete()) {
|
|
||||||
LOG.error("Could not delete temporary file: {}", newFile.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishUploadFinishedEvent(fileUploadId);
|
}
|
||||||
|
|
||||||
|
protected static void tryToCloseIOStream(final InputStream inputStream) {
|
||||||
|
if (inputStream != null) {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (final IOException e1) {
|
||||||
|
LOG.error("Closing input stream caused an exception {}", e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class TransferArtifactToRepositoryRunnable implements Runnable {
|
||||||
|
private final InputStream inputStream;
|
||||||
|
private final FileUploadId fileUploadId;
|
||||||
|
private final String mimeType;
|
||||||
|
private final UI vaadinUi;
|
||||||
|
|
||||||
|
public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId,
|
||||||
|
final String mimeType, final UI vaadinUi) {
|
||||||
|
this.inputStream = inputStream;
|
||||||
|
this.fileUploadId = fileUploadId;
|
||||||
|
this.mimeType = mimeType;
|
||||||
|
this.vaadinUi = vaadinUi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
UI.setCurrent(vaadinUi);
|
||||||
|
streamToRepository();
|
||||||
|
} catch (final RuntimeException e) {
|
||||||
|
publishUploadFailedEvent(fileUploadId, i18n.getMessage("message.upload.failed"), e);
|
||||||
|
LOG.error("Failed to transfer file to repository", e);
|
||||||
|
} finally {
|
||||||
|
tryToCloseIOStream(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void streamToRepository() {
|
||||||
|
if (fileUploadId == null) {
|
||||||
|
throw new ArtifactUploadFailedException();
|
||||||
|
}
|
||||||
|
final String filename = fileUploadId.getFilename();
|
||||||
|
LOG.info("Transfering file {} directly to repository", filename);
|
||||||
|
final Artifact artifact = uploadArtifact(filename).orElseThrow(ArtifactUploadFailedException::new);
|
||||||
|
if (isUploadInterrupted()) {
|
||||||
|
handleUploadFailure(artifact);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
publishUploadSucceeded(fileUploadId, artifact.getSize());
|
||||||
|
publishUploadFinishedEvent(fileUploadId);
|
||||||
|
publishArtifactsChanged(fileUploadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Artifact> uploadArtifact(final String filename) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(artifactManagement.create(inputStream, fileUploadId.getSoftwareModuleId(),
|
||||||
|
filename, null, null, true, mimeType, -1));
|
||||||
|
} catch (final ArtifactUploadFailedException | InvalidSHA1HashException | InvalidMD5HashException e) {
|
||||||
|
LOG.error("Failed to transfer file to repository", e);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUploadFailure(final Artifact artifact) {
|
||||||
|
Exception exception;
|
||||||
|
int tries = 0;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
artifactManagement.delete(artifact.getId());
|
||||||
|
return;
|
||||||
|
} catch (final RuntimeException e) {
|
||||||
|
exception = e;
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
} while (tries < 5);
|
||||||
|
LOG.error("Failed to delete artifact from repository after upload was interrupted", exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ package org.eclipse.hawkbit.ui.artifacts.upload;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
@@ -72,26 +74,28 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final OutputStream getOutputStream() {
|
public final OutputStream getOutputStream() {
|
||||||
|
if (isUploadInterrupted()) {
|
||||||
|
return ByteStreams.nullOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
// we return the outputstream so we cannot close it here
|
// we return the outputstream so we cannot close it here
|
||||||
@SuppressWarnings("squid:S2095")
|
@SuppressWarnings("squid:S2095")
|
||||||
OutputStream outputStream = ByteStreams.nullOutputStream();
|
final PipedOutputStream outputStream = new PipedOutputStream();
|
||||||
|
PipedInputStream inputStream = null;
|
||||||
try {
|
try {
|
||||||
outputStream = createOutputStreamForTempFile();
|
inputStream = new PipedInputStream(outputStream);
|
||||||
publishUploadProgressEvent(fileUploadId, 0, fileSize, getTempFilePath());
|
publishUploadProgressEvent(fileUploadId, 0, fileSize);
|
||||||
|
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
LOG.error("Creating temp file for upload failed {}.", e);
|
LOG.error("Creating piped Stream failed {}.", e);
|
||||||
try {
|
tryToCloseIOStream(outputStream);
|
||||||
outputStream.close();
|
tryToCloseIOStream(inputStream);
|
||||||
} catch (final IOException e1) {
|
|
||||||
LOG.error("Closing output stream caused an exception {}", e1);
|
|
||||||
}
|
|
||||||
|
|
||||||
setFailureReasonUploadFailed();
|
setFailureReasonUploadFailed();
|
||||||
setUploadInterrupted();
|
setUploadInterrupted();
|
||||||
|
getUploadState().updateFileUploadProgress(fileUploadId,
|
||||||
|
new FileUploadProgress(fileUploadId, FileUploadStatus.UPLOAD_FAILED));
|
||||||
|
return ByteStreams.nullOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +128,7 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
publishUploadProgressEvent(fileUploadId, event.getBytesReceived(), event.getContentLength(), getTempFilePath());
|
publishUploadProgressEvent(fileUploadId, event.getBytesReceived(), event.getContentLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,8 +141,6 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
|||||||
@Override
|
@Override
|
||||||
public void streamingFinished(final StreamingEndEvent event) {
|
public void streamingFinished(final StreamingEndEvent event) {
|
||||||
assertStateConsistency(fileUploadId, event.getFileName());
|
assertStateConsistency(fileUploadId, event.getFileName());
|
||||||
|
|
||||||
transferArtifactToRepository(fileUploadId, event.getContentLength(), mimeType, getTempFilePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,6 +159,7 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
|||||||
} else {
|
} else {
|
||||||
publishUploadFailedEvent(fileUploadId, event.getException());
|
publishUploadFailedEvent(fileUploadId, event.getException());
|
||||||
}
|
}
|
||||||
|
setUploadInterrupted();
|
||||||
publishUploadFinishedEvent(fileUploadId);
|
publishUploadFinishedEvent(fileUploadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ package org.eclipse.hawkbit.ui.artifacts.upload;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
@@ -51,7 +53,6 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
|
|
||||||
private volatile String mimeType;
|
|
||||||
private volatile FileUploadId fileUploadId;
|
private volatile FileUploadId fileUploadId;
|
||||||
|
|
||||||
FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement,
|
FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement,
|
||||||
@@ -70,12 +71,12 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
public void uploadStarted(final StartedEvent event) {
|
public void uploadStarted(final StartedEvent event) {
|
||||||
// reset internal state here because instance is reused for next upload!
|
// reset internal state here because instance is reused for next upload!
|
||||||
resetState();
|
resetState();
|
||||||
this.mimeType = null;
|
|
||||||
this.fileUploadId = null;
|
this.fileUploadId = null;
|
||||||
|
|
||||||
assertThatOneSoftwareModuleIsSelected();
|
assertThatOneSoftwareModuleIsSelected();
|
||||||
|
|
||||||
// selected software module at the time of this callback is considered
|
// selected software module at the time of this callback is
|
||||||
|
// considered
|
||||||
SoftwareModule softwareModule = null;
|
SoftwareModule softwareModule = null;
|
||||||
final Optional<Long> selectedSoftwareModuleId = getUploadState().getSelectedBaseSwModuleId();
|
final Optional<Long> selectedSoftwareModuleId = getUploadState().getSelectedBaseSwModuleId();
|
||||||
final Long softwareModuleId = selectedSoftwareModuleId.orElse(null);
|
final Long softwareModuleId = selectedSoftwareModuleId.orElse(null);
|
||||||
@@ -84,7 +85,6 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.fileUploadId = new FileUploadId(event.getFilename(), softwareModule);
|
this.fileUploadId = new FileUploadId(event.getFilename(), softwareModule);
|
||||||
this.mimeType = event.getMIMEType();
|
|
||||||
|
|
||||||
if (getUploadState().isFileInUploadState(this.fileUploadId)) {
|
if (getUploadState().isFileInUploadState(this.fileUploadId)) {
|
||||||
setFailureReasonUploadFailed();
|
setFailureReasonUploadFailed();
|
||||||
@@ -131,26 +131,23 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
|
|
||||||
// we return the outputstream so we cannot close it here
|
// we return the outputstream so we cannot close it here
|
||||||
@SuppressWarnings("squid:S2095")
|
@SuppressWarnings("squid:S2095")
|
||||||
OutputStream outputStream = ByteStreams.nullOutputStream();
|
final PipedOutputStream outputStream = new PipedOutputStream();
|
||||||
|
PipedInputStream inputStream = null;
|
||||||
try {
|
try {
|
||||||
outputStream = createOutputStreamForTempFile();
|
inputStream = new PipedInputStream(outputStream);
|
||||||
this.mimeType = mimeType;
|
publishUploadProgressEvent(fileUploadId, 0, 0);
|
||||||
publishUploadProgressEvent(fileUploadId, 0, 0, getTempFilePath());
|
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
|
||||||
|
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
LOG.error("Creating temp file for upload failed {}.", e);
|
LOG.error("Creating piped Stream failed {}.", e);
|
||||||
if (outputStream != null) {
|
tryToCloseIOStream(outputStream);
|
||||||
try {
|
tryToCloseIOStream(inputStream);
|
||||||
outputStream.close();
|
|
||||||
} catch (final IOException e1) {
|
|
||||||
LOG.error("Closing output stream caused an exception {}", e1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFailureReasonUploadFailed();
|
setFailureReasonUploadFailed();
|
||||||
setUploadInterrupted();
|
setUploadInterrupted();
|
||||||
|
getUploadState().updateFileUploadProgress(fileUploadId,
|
||||||
|
new FileUploadProgress(fileUploadId, FileUploadStatus.UPLOAD_FAILED));
|
||||||
|
uiNotification.displayWarning("try again");
|
||||||
|
return ByteStreams.nullOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +170,7 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
publishUploadProgressEvent(fileUploadId, readBytes, contentLength, getTempFilePath());
|
publishUploadProgressEvent(fileUploadId, readBytes, contentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,8 +187,6 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assertStateConsistency(fileUploadId, event.getFilename());
|
assertStateConsistency(fileUploadId, event.getFilename());
|
||||||
|
|
||||||
transferArtifactToRepository(fileUploadId, event.getLength(), mimeType, getTempFilePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,6 +215,7 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
|||||||
} else {
|
} else {
|
||||||
publishUploadFailedEvent(fileUploadId, event.getReason());
|
publishUploadFailedEvent(fileUploadId, event.getReason());
|
||||||
}
|
}
|
||||||
|
setUploadInterrupted();
|
||||||
publishUploadFinishedEvent(fileUploadId);
|
publishUploadFinishedEvent(fileUploadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,27 @@ public class FileUploadProgress implements Serializable {
|
|||||||
this.fileUploadStatus = fileUploadStatus;
|
this.fileUploadStatus = fileUploadStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link FileUploadProgress} instance.
|
||||||
|
*
|
||||||
|
* @param fileUploadId
|
||||||
|
* the {@link FileUploadId} to which this progress information
|
||||||
|
* belongs.
|
||||||
|
* @param fileUploadStatus
|
||||||
|
* the {@link FileUploadStatus} of this progress
|
||||||
|
* @param bytesRead
|
||||||
|
* number of bytes read
|
||||||
|
* @param contentLength
|
||||||
|
* size of the file in bytes
|
||||||
|
*/
|
||||||
|
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus,
|
||||||
|
final long bytesRead, final long contentLength) {
|
||||||
|
this.fileUploadId = fileUploadId;
|
||||||
|
this.fileUploadStatus = fileUploadStatus;
|
||||||
|
this.contentLength = contentLength;
|
||||||
|
this.bytesRead = bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link FileUploadProgress} instance.
|
* Creates a new {@link FileUploadProgress} instance.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.ui.artifacts.upload;
|
|||||||
|
|
||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
@@ -179,39 +178,28 @@ public class UploadDropAreaLayout extends AbstractComponent {
|
|||||||
private void uploadFilesForSoftwareModule(final Html5File[] files, final Long softwareModuleId) {
|
private void uploadFilesForSoftwareModule(final Html5File[] files, final Long softwareModuleId) {
|
||||||
final SoftwareModule softwareModule = softwareManagement.get(softwareModuleId).orElse(null);
|
final SoftwareModule softwareModule = softwareManagement.get(softwareModuleId).orElse(null);
|
||||||
|
|
||||||
boolean isDirectory = false;
|
boolean duplicateFound = false;
|
||||||
boolean isDuplicate = false;
|
|
||||||
|
|
||||||
for (final Html5File file : files) {
|
for (final Html5File file : files) {
|
||||||
|
if (artifactUploadState.isFileInUploadState(file.getFileName(), softwareModule)) {
|
||||||
isDirectory = isDirectory(file);
|
duplicateFound = true;
|
||||||
isDuplicate = artifactUploadState.isFileInUploadState(file.getFileName(), softwareModule);
|
} else {
|
||||||
|
|
||||||
if (!isDirectory && !isDuplicate) {
|
|
||||||
file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(),
|
file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(),
|
||||||
multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement,
|
multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement,
|
||||||
i18n));
|
i18n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDirectory && isDuplicate) {
|
if (duplicateFound) {
|
||||||
uiNotification.displayValidationError(i18n.getMessage("message.no.duplicateFiles") + "<br>"
|
uiNotification.displayValidationError(
|
||||||
+ i18n.getMessage("message.no.directory.upload"));
|
i18n.getMessage("message.no.duplicateFiles"));
|
||||||
} else if (isDirectory) {
|
|
||||||
uiNotification.displayValidationError(i18n.getMessage("message.no.directory.upload"));
|
|
||||||
} else if (isDuplicate) {
|
|
||||||
uiNotification.displayValidationError(i18n.getMessage("message.no.duplicateFiles"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDirectory(final Html5File file) {
|
|
||||||
return StringUtils.isBlank(file.getType()) && file.getFileSize() % 4096 == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validate(final DragAndDropEvent event) {
|
private boolean validate(final DragAndDropEvent event) {
|
||||||
// check if drop is valid.If valid ,check if software module is
|
// check if drop is valid.If valid ,check if software module is
|
||||||
// selected.
|
// selected.
|
||||||
if (!isFilesDropped(event)) {
|
if (!isFilesDropped(event)) {
|
||||||
uiNotification.displayValidationError(i18n.getMessage(UIMessageIdProvider.MESSAGE_ACTION_NOT_ALLOWED));
|
uiNotification.displayValidationError(i18n.getMessage("message.drop.onlyFiles"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return validateSoftwareModuleSelection();
|
return validateSoftwareModuleSelection();
|
||||||
|
|||||||
@@ -55,4 +55,19 @@ public final class SpringContextHelper {
|
|||||||
return context.getBean(beanClazz);
|
return context.getBean(beanClazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* method to return a certain bean by its class and name.
|
||||||
|
*
|
||||||
|
* @param beanName
|
||||||
|
* name of the beand which should be returned from the
|
||||||
|
* application context
|
||||||
|
* @param beanClazz
|
||||||
|
* class of the bean which should be returned from the
|
||||||
|
* application context
|
||||||
|
* @return the requested bean
|
||||||
|
*/
|
||||||
|
public static <T> T getBean(final String beanName, final Class<T> beanClazz) {
|
||||||
|
return context.getBean(beanName, beanClazz);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -393,6 +393,7 @@ message.error.missing.tagname = Please select tag name
|
|||||||
message.type.delete = Please unclick the distribution type {0}, then try to delete
|
message.type.delete = Please unclick the distribution type {0}, then try to delete
|
||||||
message.error.dist.set.type.update= Distribution set type is already assigned to set(s) and cannot be changed
|
message.error.dist.set.type.update= Distribution set type is already assigned to set(s) and cannot be changed
|
||||||
message.no.directory.upload = Directory upload is not supported
|
message.no.directory.upload = Directory upload is not supported
|
||||||
|
message.drop.onlyFiles = Please drop files only
|
||||||
message.delete.filter.confirm = Are you sure you want to delete custom filter?
|
message.delete.filter.confirm = Are you sure you want to delete custom filter?
|
||||||
message.delete.filter.success = Custom filter {0} deleted Successfully!
|
message.delete.filter.success = Custom filter {0} deleted Successfully!
|
||||||
message.create.filter.success = Custom filter {0} created Successfully!
|
message.create.filter.success = Custom filter {0} created Successfully!
|
||||||
|
|||||||
Reference in New Issue
Block a user