[#1510] Remove Vaadin v8 UI: Remove Libs (#1554)

Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
Avgustin Marinov
2024-01-19 12:34:42 +02:00
committed by GitHub
parent b929b86437
commit d9481ed43f
639 changed files with 0 additions and 77433 deletions

View File

@@ -1 +0,0 @@
/webapp/

View File

@@ -1,271 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import com.vaadin.shared.ui.ContentMode;
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
import org.eclipse.hawkbit.ui.error.ErrorView;
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.util.ObjectUtils;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.annotations.Widgetset;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.navigator.ViewProvider;
import com.vaadin.server.ClientConnector.DetachListener;
import com.vaadin.server.ErrorHandler;
import com.vaadin.server.Responsive;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.navigator.SpringViewProvider;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
/**
* Vaadin management UI.
*
*/
@Title("hawkBit Update Server")
@Widgetset(value = HawkbitTheme.WIDGET_SET_NAME)
@Theme(HawkbitTheme.THEME_NAME)
public abstract class AbstractHawkbitUI extends UI implements DetachListener {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(AbstractHawkbitUI.class);
private static final String EMPTY_VIEW = "";
private final VaadinMessageSource i18n;
private final UiProperties uiProperties;
private Label viewTitle;
private final DashboardMenu dashboardMenu;
private final ErrorView errorview;
private final NotificationUnreadButton notificationUnreadButton;
private final SpringViewProvider viewProvider;
private final transient ApplicationContext context;
private final transient EventPushStrategy pushStrategy;
private final transient ErrorHandler uiErrorHandler;
private final transient HawkbitEntityEventListener entityEventsListener;
protected AbstractHawkbitUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus,
final UIEventProvider eventProvider, final SpringViewProvider viewProvider,
final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview,
final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties,
final VaadinMessageSource i18n, final ErrorHandler uiErrorHandler) {
this.pushStrategy = pushStrategy;
this.viewProvider = viewProvider;
this.context = context;
this.dashboardMenu = dashboardMenu;
this.errorview = errorview;
this.notificationUnreadButton = notificationUnreadButton;
this.uiProperties = uiProperties;
this.i18n = i18n;
this.uiErrorHandler = uiErrorHandler;
this.entityEventsListener = new HawkbitEntityEventListener(eventBus, eventProvider, notificationUnreadButton);
}
@Override
public void detach(final DetachEvent event) {
LOG.debug("ManagementUI is detached uiid - {}", getUIId());
entityEventsListener.unsubscribeListeners();
if (pushStrategy != null) {
pushStrategy.clean();
clearContextListener();
}
}
private void clearContextListener() {
if (pushStrategy instanceof ApplicationListener && context instanceof AbstractApplicationContext) {
final ApplicationListener<?> listener = (ApplicationListener<?>) pushStrategy;
((AbstractApplicationContext) context).getApplicationListeners().remove(listener);
// we do not need to explicitly remove the listener from
// ApplicationEventMulticaster because it is done by
// UIBeanStore#destroy delegating to
// ApplicationListenerDetector#postProcessBeforeDestruction
}
}
@Override
protected void init(final VaadinRequest vaadinRequest) {
LOG.debug("ManagementUI init starts uiid - {}", getUI().getUIId());
if (pushStrategy != null) {
pushStrategy.init(getUI());
}
addDetachListener(this);
Responsive.makeResponsive(this);
addStyleName(ValoTheme.UI_WITH_MENU);
setResponsive(Boolean.TRUE);
final HorizontalLayout rootLayout = new HorizontalLayout();
rootLayout.setMargin(false);
rootLayout.setSpacing(false);
rootLayout.setSizeFull();
HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n);
SPDateTimeUtil.initializeFixedTimeZoneProperty(uiProperties.getFixedTimeZone());
dashboardMenu.init();
dashboardMenu.setResponsive(true);
final VerticalLayout contentVerticalLayout = new VerticalLayout();
contentVerticalLayout.setMargin(false);
contentVerticalLayout.setSpacing(false);
contentVerticalLayout.setSizeFull();
contentVerticalLayout.setStyleName("main-content");
contentVerticalLayout.addComponent(buildHeader());
contentVerticalLayout.addComponent(buildViewTitle());
final Panel content = buildContent();
contentVerticalLayout.addComponent(content);
contentVerticalLayout.setExpandRatio(content, 1.0F);
String footerNotification = uiProperties.getNotification().getText();
if (!ObjectUtils.isEmpty(footerNotification)) {
contentVerticalLayout.addComponent(buildFooterNotification(footerNotification));
}
rootLayout.addComponent(dashboardMenu);
rootLayout.addComponent(contentVerticalLayout);
rootLayout.setExpandRatio(contentVerticalLayout, 1.0F);
setContent(rootLayout);
final Navigator navigator = new Navigator(this, content);
navigator.addViewChangeListener(new ViewChangeListener() {
private static final long serialVersionUID = 1L;
@Override
public boolean beforeViewChange(final ViewChangeEvent event) {
return true;
}
@Override
public void afterViewChange(final ViewChangeEvent event) {
final DashboardMenuItem view = dashboardMenu.getByViewName(event.getViewName());
dashboardMenu.postViewChange(new PostViewChangeEvent(view));
if (view == null) {
viewTitle.setCaption(null);
return;
}
viewTitle.setCaption(view.getDashboardCaptionLong());
}
});
navigator.setErrorView(errorview);
navigator.addView(EMPTY_VIEW, new Navigator.EmptyView());
navigator.addProvider(new ManagementViewProvider());
setNavigator(navigator);
if (UI.getCurrent().getErrorHandler() == null) {
UI.getCurrent().setErrorHandler(uiErrorHandler);
}
LOG.debug("Current locale of the application is : {}", getLocale());
}
private static Component buildFooterNotification(String text) {
Label notification = new Label();
notification.setValue(text);
notification.setWidth("100%");
notification.setContentMode(ContentMode.HTML);
return notification;
}
private static Panel buildContent() {
final Panel content = new Panel();
content.setSizeFull();
content.setStyleName("view-content");
return content;
}
private HorizontalLayout buildViewTitle() {
final HorizontalLayout viewHeadercontent = new HorizontalLayout();
viewHeadercontent.setMargin(false);
viewHeadercontent.setSpacing(false);
viewHeadercontent.setWidth("100%");
viewHeadercontent.addStyleName("view-header-layout");
viewTitle = new Label();
viewTitle.setWidth("100%");
viewTitle.setStyleName("header-content");
viewHeadercontent.addComponent(viewTitle);
viewHeadercontent.addComponent(notificationUnreadButton);
viewHeadercontent.setComponentAlignment(notificationUnreadButton, Alignment.MIDDLE_RIGHT);
return viewHeadercontent;
}
private static Component buildHeader() {
final CssLayout cssLayout = new CssLayout();
cssLayout.setStyleName("view-header");
return cssLayout;
}
private class ManagementViewProvider implements ViewProvider {
private static final long serialVersionUID = 1L;
private static final String DEFAULT_PARAMETER_SEPARATOR = "/";
@Override
public String getViewName(final String viewAndParameters) {
final int paramsDelimeterIndex = viewAndParameters.indexOf(DEFAULT_PARAMETER_SEPARATOR);
final String viewName = paramsDelimeterIndex != -1 ? viewAndParameters.substring(0, paramsDelimeterIndex)
: viewAndParameters;
return viewProvider.getViewName(getStartView(viewName));
}
@Override
public View getView(final String viewName) {
return viewProvider.getView(viewName);
}
private String getStartView(final String viewName) {
final DashboardMenuItem view = dashboardMenu.getByViewName(viewName);
if ("".equals(viewName) && !dashboardMenu.isAccessibleViewsEmpty()) {
return dashboardMenu.getInitialViewName();
}
if (view == null || dashboardMenu.isAccessDenied(viewName)) {
return " ";
}
return viewName;
}
}
}

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2015 Bosch Software Innovations GmbH and others
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
-->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd">
<module>
<!-- This file is automatically updated based on new dependencies by the goal "vaadin:update-widgetset". -->
<inherits name="com.vaadin.DefaultWidgetSet" />
<inherits name="org.vaadin.alump.distributionbar.gwt.DistributionBarWidgetset" />
<inherits name="org.eclipse.hawkbit.ui.filtermanagement.TextFieldSuggestionBox" />
<inherits name="org.eclipse.hawkbit.ui.rollout.groupschart.GroupsPieChart" />
<inherits
name="org.eclipse.hawkbit.ui.common.grid.selection.RangeSelectionWidgetset" />
<inherits
name="org.eclipse.hawkbit.ui.common.notification.ParallelNotificationWidgetset" />
</module>

View File

@@ -1,177 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayloadIdentifier;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.springframework.util.CollectionUtils;
import org.vaadin.spring.events.Event;
import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.spring.events.EventBusListenerMethodFilter;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.vaadin.ui.UI;
/**
* Listener for internal and remote entity modified events. Keeps a cache of the
* events coming from UI in order to suppress the corresponding remote events.
*/
public class HawkbitEntityEventListener {
private final UIEventBus eventBus;
private final UIEventProvider eventProvider;
private final NotificationUnreadButton notificationUnreadButton;
private final Cache<EntityModifiedEventPayloadIdentifier, Collection<Long>> uiOriginatedEventsCache;
private final List<Object> eventListeners;
HawkbitEntityEventListener(final UIEventBus eventBus, final UIEventProvider eventProvider,
final NotificationUnreadButton notificationUnreadButton) {
this.eventBus = eventBus;
this.eventProvider = eventProvider;
this.notificationUnreadButton = notificationUnreadButton;
this.uiOriginatedEventsCache = Caffeine.newBuilder().expireAfterWrite(10, SECONDS).build();
this.eventListeners = new ArrayList<>();
registerEventListeners();
}
private void registerEventListeners() {
eventListeners.add(new EntityModifiedListener());
eventListeners.add(new RemoteEventListener());
}
private class EntityModifiedListener {
/**
* Constructor for EntityModifiedListener
*/
public EntityModifiedListener() {
eventBus.subscribe(this, EventTopics.ENTITY_MODIFIED);
}
@EventBusListenerMethod(scope = EventScope.UI, filter = IgnoreRemoteEventsFilter.class)
private void onEntityModifiedEvent(final EntityModifiedEventPayload eventPayload) {
// parentId is ignored here because entityIds should be unique
uiOriginatedEventsCache.asMap().merge(EntityModifiedEventPayloadIdentifier.of(eventPayload),
eventPayload.getEntityIds(), (oldEntityIds, newEntityIds) -> Stream
.concat(oldEntityIds.stream(), newEntityIds.stream()).collect(Collectors.toList()));
}
}
/**
* Ignore remote events filter
*/
public static class IgnoreRemoteEventsFilter implements EventBusListenerMethodFilter {
@Override
public boolean filter(final Event<?> event) {
return !event.getSource().equals(UI.getCurrent());
}
}
private class RemoteEventListener {
/**
* Constructor for RemoteEventListener
*/
public RemoteEventListener() {
eventBus.subscribe(this, EventTopics.REMOTE_EVENT_RECEIVED);
}
@EventBusListenerMethod(scope = EventScope.UI)
private void onRemoteEventReceived(final EntityModifiedEventPayload eventPayload) {
if (eventPayload.getEntityType() == null || eventPayload.getEntityModifiedEventType() == null
|| CollectionUtils.isEmpty(eventPayload.getEntityIds())) {
return;
}
getEventPayloadIdentifierFromProvider(eventPayload).ifPresent(eventPayloadIdentifier -> {
final Collection<Long> remotelyModifiedEntityIds = getRemotelyModifiedEntityIds(eventPayloadIdentifier,
eventPayload.getEntityIds());
if (!remotelyModifiedEntityIds.isEmpty()) {
final EntityModifiedEventPayload remoteEventPayload = EntityModifiedEventPayload
.of(eventPayloadIdentifier, eventPayload.getParentId(), remotelyModifiedEntityIds);
if (eventPayloadIdentifier.shouldBeDeffered()) {
notificationUnreadButton.incrementUnreadNotification(
eventPayloadIdentifier.getNotificationType(), remoteEventPayload);
} else {
eventBus.publish(EventTopics.ENTITY_MODIFIED, UI.getCurrent(), remoteEventPayload);
}
}
});
}
private Optional<EntityModifiedEventPayloadIdentifier> getEventPayloadIdentifierFromProvider(
final EntityModifiedEventPayload eventPayload) {
return eventProvider.getEvents().values().stream().filter(providedIdentifier -> providedIdentifier
.equals(EntityModifiedEventPayloadIdentifier.of(eventPayload))).findAny();
}
private Collection<Long> getRemotelyModifiedEntityIds(
final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier,
final Collection<Long> remoteEventEntityIds) {
final Collection<Long> cachedEventEntityIds = uiOriginatedEventsCache.getIfPresent(eventPayloadIdentifier);
if (CollectionUtils.isEmpty(cachedEventEntityIds)) {
return remoteEventEntityIds;
}
final Collection<Long> commonEntityIds = getCommonEntityIds(cachedEventEntityIds, remoteEventEntityIds);
if (!commonEntityIds.isEmpty()) {
updateCache(eventPayloadIdentifier, cachedEventEntityIds, commonEntityIds);
remoteEventEntityIds.removeAll(commonEntityIds);
}
return remoteEventEntityIds;
}
private Collection<Long> getCommonEntityIds(final Collection<Long> cachedEventEntityIds,
final Collection<Long> remoteEventEntityIds) {
final List<Long> commonEntityIds = new ArrayList<>(cachedEventEntityIds);
commonEntityIds.retainAll(remoteEventEntityIds);
return commonEntityIds;
}
private void updateCache(final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier,
final Collection<Long> cachedEventEntityIds, final Collection<Long> commonEntityIds) {
final List<Long> updatedCachedEventEntityIds = new ArrayList<>(cachedEventEntityIds);
updatedCachedEventEntityIds.removeAll(commonEntityIds);
if (updatedCachedEventEntityIds.isEmpty()) {
uiOriginatedEventsCache.invalidate(eventPayloadIdentifier);
} else {
uiOriginatedEventsCache.put(eventPayloadIdentifier, updatedCachedEventEntityIds);
}
}
}
void unsubscribeListeners() {
eventListeners.forEach(eventBus::unsubscribe);
}
}

View File

@@ -1,71 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import java.util.Locale;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.server.CustomizedSystemMessages;
import com.vaadin.server.SystemMessages;
import com.vaadin.server.SystemMessagesInfo;
import com.vaadin.server.SystemMessagesProvider;
/**
* {@link SystemMessagesProvider} that localizes Vaadin system messages.
*
*/
public class LocalizedSystemMessagesProvider implements SystemMessagesProvider {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final UiProperties uiProperties;
/**
* Constructor for LocalizedSystemMessagesProvider
*
* @param uiProperties
* Properties to determine the available Locales
* @param i18n
* Message source used for localization
*/
public LocalizedSystemMessagesProvider(final UiProperties uiProperties, final VaadinMessageSource i18n) {
this.i18n = i18n;
this.uiProperties = uiProperties;
}
private SystemMessages getLocalizedSystemMessages(final VaadinMessageSource i18n, final Locale local) {
final CustomizedSystemMessages messages = new CustomizedSystemMessages();
final Locale desiredLocale = HawkbitCommonUtil.getLocaleToBeUsed(uiProperties.getLocalization(), local);
messages.setSessionExpiredCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION));
messages.setSessionExpiredMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE));
messages.setCommunicationErrorCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_CAPTION));
messages.setCommunicationErrorMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_MESSAGE));
messages.setInternalErrorCaption(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_CAPTION));
messages.setInternalErrorMessage(
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_MESSAGE));
return messages;
}
@Override
public SystemMessages getSystemMessages(final SystemMessagesInfo systemMessagesInfo) {
return getLocalizedSystemMessages(i18n, systemMessagesInfo.getLocale());
}
}

View File

@@ -1,267 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.PermissionService;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.ui.common.data.mappers.TargetToProxyTargetMapper;
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetFilterStateDataSupplier;
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetFilterStateDataSupplierImpl;
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplier;
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplierImpl;
import org.eclipse.hawkbit.ui.error.HawkbitUIErrorHandler;
import org.eclipse.hawkbit.ui.error.extractors.ArtifactEncryptionErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.ConstraintViolationErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.EntityNotFoundErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.IncompatibleTargetTypeErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.InsufficientPermissionErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.InvalidDistributionSetErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.AssignmentQuotaExceededErrorExtractor;
import org.eclipse.hawkbit.ui.error.extractors.UiErrorDetailsExtractor;
import org.eclipse.hawkbit.ui.error.extractors.UploadErrorExtractor;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.vaadin.spring.servlet.Vaadin4SpringServlet;
import com.vaadin.server.ErrorHandler;
import com.vaadin.server.SystemMessagesProvider;
import com.vaadin.server.VaadinServlet;
import com.vaadin.spring.annotation.UIScope;
/**
* Enables UI components for the Management UI.
*
*/
@Configuration
@ComponentScan
@EnableConfigurationProperties(UiProperties.class)
@PropertySource("classpath:/hawkbit-ui-defaults.properties")
public class MgmtUiConfiguration {
/**
* Permission checker for UI.
*
* @param permissionService
* PermissionService
*
* @return Permission checker for UI
*/
@Bean
@ConditionalOnMissingBean
SpPermissionChecker spPermissionChecker(final PermissionService permissionService) {
return new SpPermissionChecker(permissionService);
}
/**
* Utility for Vaadin messages source.
*
* @param source
* Delegate MessageSource
*
* @return Vaadin messages source utility
*/
@Bean
@ConditionalOnMissingBean
VaadinMessageSource messageSourceVaadin(final MessageSource source) {
return new VaadinMessageSource(source);
}
/**
* Localized system message provider bean.
*
* @param uiProperties
* UiProperties
* @param i18n
* VaadinMessageSource
*
* @return Localized system message provider
*/
@Bean
@ConditionalOnMissingBean
SystemMessagesProvider systemMessagesProvider(final UiProperties uiProperties, final VaadinMessageSource i18n) {
return new LocalizedSystemMessagesProvider(uiProperties, i18n);
}
/**
* UI Error handler bean.
*
* @param i18n
* VaadinMessageSource
* @param uiErrorDetailsExtractor
* ui error details extractors
*
* @return UI Error handler
*/
@Bean
@ConditionalOnMissingBean
ErrorHandler uiErrorHandler(final VaadinMessageSource i18n,
final List<UiErrorDetailsExtractor> uiErrorDetailsExtractors) {
return new HawkbitUIErrorHandler(i18n, uiErrorDetailsExtractors);
}
/**
* UI Upload Error details extractor bean.
*
* @return UI Upload Error details extractor
*/
@Bean
UiErrorDetailsExtractor uploadErrorExtractor() {
return new UploadErrorExtractor();
}
/**
* UI ConstraintViolation Error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI ConstraintViolation Error details extractor
*/
@Bean
UiErrorDetailsExtractor constraintViolationErrorExtractor(final VaadinMessageSource i18n) {
return new ConstraintViolationErrorExtractor(i18n);
}
/**
* UI Entity not found Error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI EntityNotFound Error details extractor
*/
@Bean
UiErrorDetailsExtractor entityNotFoundErrorExtractor(final VaadinMessageSource i18n) {
return new EntityNotFoundErrorExtractor(i18n);
}
/**
* UI incompatible Target Type error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI IncompatibleTargetType Error details extractor
*/
@Bean
UiErrorDetailsExtractor incompatibleTargetTypeErrorExtractor(final VaadinMessageSource i18n) {
return new IncompatibleTargetTypeErrorExtractor(i18n);
}
/**
* UI Insufficient Permission Error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI InsufficientPermission Error details extractor
*/
@Bean
UiErrorDetailsExtractor insufficientPermissionErrorExtractor(final VaadinMessageSource i18n) {
return new InsufficientPermissionErrorExtractor(i18n);
}
/**
* Details extractor bean for action not possible because of distribution
* set is invalid.
*
* @param i18n
* VaadinMessageSource
* @return UI invalid distributionset Error details extractor
*/
@Bean
UiErrorDetailsExtractor invalidDistributionSetErrorExtractor(final VaadinMessageSource i18n) {
return new InvalidDistributionSetErrorExtractor(i18n);
}
/**
* UI Artifact ecnryption operations Error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI Artifact ecnryption operations Error details extractor
*/
@Bean
UiErrorDetailsExtractor artifactEncryptionErrorExtractor(final VaadinMessageSource i18n) {
return new ArtifactEncryptionErrorExtractor(i18n);
}
/**
* UI Assignment Quota exceeded Error details extractor bean.
*
* @param i18n
* VaadinMessageSource
* @return UI Assignment Quota exceeded Error details extractor
*/
@Bean
UiErrorDetailsExtractor assignmentQuotaExceededErrorExtractor(final VaadinMessageSource i18n) {
return new AssignmentQuotaExceededErrorExtractor(i18n);
}
/**
* Vaadin4Spring servlet bean.
*
* @return Vaadin servlet for Spring
*/
@Bean
public VaadinServlet vaadinServlet() {
return new Vaadin4SpringServlet();
}
/**
* UI target entity mapper bean.
*
* @param i18n
* VaadinMessageSource
* @return UI target entity mapper
*/
@Bean
public TargetToProxyTargetMapper targetToProxyTargetMapper(final VaadinMessageSource i18n) {
return new TargetToProxyTargetMapper(i18n);
}
/**
* UI Management target data supplier bean.
*
* @param targetManagement
* TargetManagement
* @param targetToProxyTargetMapper
* UI target entity mapper
* @return UI target data supplier for Management view
*/
@Bean
@ConditionalOnMissingBean
@UIScope
public TargetManagementStateDataSupplier targetManagementStateDataSupplier(final TargetManagement targetManagement,
final TargetToProxyTargetMapper targetToProxyTargetMapper) {
return new TargetManagementStateDataSupplierImpl(targetManagement, targetToProxyTargetMapper);
}
/**
* UI Filter target data supplier bean.
*
* @param targetManagement
* TargetManagement
* @param targetToProxyTargetMapper
* UI target entity mapper
* @return UI target data supplier for Filter view
*/
@Bean
@ConditionalOnMissingBean
@UIScope
public TargetFilterStateDataSupplier targetFilterStateDataSupplier(final TargetManagement targetManagement,
final TargetToProxyTargetMapper targetToProxyTargetMapper) {
return new TargetFilterStateDataSupplierImpl(targetManagement, targetToProxyTargetMapper);
}
}

View File

@@ -1,190 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import java.io.Serializable;
import org.eclipse.hawkbit.im.authentication.PermissionService;
import org.eclipse.hawkbit.im.authentication.SpPermission;
/**
* Bean which contains all permissions.
*
*/
public class SpPermissionChecker implements Serializable {
private static final long serialVersionUID = 1L;
protected transient PermissionService permissionService;
protected SpPermissionChecker(final PermissionService permissionService) {
this.permissionService = permissionService;
}
/**
* Gets the read Target and repository Permission.
*
* @return TARGET_REPOSITORY_READ boolean value
*/
public boolean hasTargetAndRepositoryReadPermission() {
return hasTargetReadPermission() && hasReadRepositoryPermission();
}
/**
* Gets the read Target Permission.
*
* @return READ_TARGET boolean value
*/
public boolean hasTargetReadPermission() {
return permissionService.hasPermission(SpPermission.READ_TARGET);
}
/**
* Gets the create Target Permission.
*
* @return READ_TARGET boolean value
*/
public boolean hasCreateTargetPermission() {
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.CREATE_TARGET);
}
/**
* Gets the update Target Permission.
*
* @return READ_TARGET boolean value
*/
public boolean hasUpdateTargetPermission() {
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.UPDATE_TARGET);
}
/**
* Gets the delete Target Permission.
*
* @return READ_TARGET boolean value
*/
public boolean hasDeleteTargetPermission() {
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.DELETE_TARGET);
}
/**
* Gets the READ Repository Permission.
*
* @return READ_REPOSITORY boolean value
*/
public boolean hasReadRepositoryPermission() {
return permissionService.hasPermission(SpPermission.READ_REPOSITORY);
}
/**
* Has the download Repository Artifact Permission.
*
* @return DOWNLOAD_REPOSITORY_ARTIFACT boolean value
*/
public boolean hasDownloadRepositoryPermission() {
return permissionService.hasPermission(SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT);
}
/**
* Gets the create Repository Permission.
*
* @return CREATE_REPOSITORY boolean value
*/
public boolean hasCreateRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.CREATE_REPOSITORY);
}
/**
* Gets the update Repository Permission.
*
* @return UPDATE_REPOSITORY boolean value
*/
public boolean hasUpdateRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.UPDATE_REPOSITORY);
}
/**
* Has the delete Repository Permission.
*
* @return DELETE_REPOSITORY boolean value
*/
public boolean hasDeleteRepositoryPermission() {
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.DELETE_REPOSITORY);
}
/**
* Has the rollout update permission.
*
* @return permission for rollout update
*/
public boolean hasRolloutUpdatePermission() {
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.UPDATE_ROLLOUT);
}
/**
* @return <code>true</code> if rollout create permission
*/
public boolean hasRolloutCreatePermission() {
return hasTargetReadPermission() && hasReadRepositoryPermission()
&& permissionService.hasPermission(SpPermission.CREATE_ROLLOUT);
}
/**
* @return <code>true</code> if rollout read permission
*/
public boolean hasRolloutReadPermission() {
return permissionService.hasPermission(SpPermission.READ_ROLLOUT);
}
/**
* @return <code>true</code> if rollout delete permission
*/
public boolean hasRolloutDeletePermission() {
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.DELETE_ROLLOUT);
}
/**
* @return <code>true</code> if rollout handle permission.
*/
public boolean hasRolloutHandlePermission() {
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.HANDLE_ROLLOUT);
}
/**
* @return permission to read rollout targets
*/
public boolean hasRolloutTargetsReadPermission() {
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.READ_ROLLOUT);
}
/**
*
* @return <code>true</code> if rollout can be approved by the user.
*/
public boolean hasRolloutApprovalPermission() {
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.APPROVE_ROLLOUT);
}
/**
*
* @return <code>true</code> if auto assignment can be added/updated to target filter
*/
public boolean hasAutoAssignmentUpdatePermission() {
return hasUpdateTargetPermission() && hasReadRepositoryPermission();
}
/**
*
* @return <code>true</code> if default invalidation of distribution set is
* allowed
*/
public boolean hasDistributionSetInvalidatePermission() {
return hasUpdateRepositoryPermission() && hasUpdateTargetPermission();
}
}

View File

@@ -1,627 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for Management UI customization.
*
*/
@ConfigurationProperties("hawkbit.server.ui")
public class UiProperties implements Serializable {
private static final long serialVersionUID = 1L;
private boolean gravatar;
private String fixedTimeZone;
private final Localization localization = new Localization();
private final Links links = new Links();
private final Demo demo = new Demo();
private final Event event = new Event();
private final Notification notification = new Notification();
/**
* @return True if menu item has gravatar else false
*/
public boolean isGravatar() {
return gravatar;
}
/**
* Sets the gravatar
*
* @param gravatar
* Menu icon
*/
public void setGravatar(final boolean gravatar) {
this.gravatar = gravatar;
}
/**
* @return Fixed time zone if unknown then GMT
*/
public String getFixedTimeZone() {
return fixedTimeZone;
}
/**
* Sets the fixed time zone
*
* @param fixedTimeZone
* Date time zone
*/
public void setFixedTimeZone(final String fixedTimeZone) {
this.fixedTimeZone = fixedTimeZone;
}
/**
* Localization information
*/
public static class Localization implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Default localization
*/
private Locale defaultLocal = Locale.ENGLISH;
/**
* List of available localizations
*/
private List<Locale> availableLocals = Collections.singletonList(Locale.ENGLISH);
/**
* @return Default locale
*/
public Locale getDefaultLocal() {
return defaultLocal;
}
/**
* @return List of available locale
*/
public List<Locale> getAvailableLocals() {
return availableLocals;
}
/**
* Sets the default locale
*
* @param defaultLocal
* Locale
*/
public void setDefaultLocal(final Locale defaultLocal) {
this.defaultLocal = defaultLocal;
}
/**
* Sets the all available locale
*
* @param availableLocals
* List of locale
*/
public void setAvailableLocals(final List<Locale> availableLocals) {
this.availableLocals = availableLocals;
}
}
/**
* Demo account login information.
*
*/
public static class Demo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Demo tenant.
*/
private String tenant = "";
/**
* Demo user name.
*/
private String user = "";
/**
* Demo user password.
*/
// Exception squid:S2068 - Empty password
@SuppressWarnings({ "squid:S2068" })
private String password = "";
private String disclaimer = "";
/**
* @return password
*/
public String getPassword() {
return password;
}
/**
* @return tenant
*/
public String getTenant() {
return tenant;
}
/**
* @return username
*/
public String getUser() {
return user;
}
/**
* Sets the login password
*
* @param password
* Password value
*/
public void setPassword(final String password) {
this.password = password;
}
/**
* Sets the tenant
*
* @param tenant
* Tenant value
*/
public void setTenant(final String tenant) {
this.tenant = tenant;
}
/**
* Sets the login user
*
* @param user
* username
*/
public void setUser(final String user) {
this.user = user;
}
/**
* @return disclaimer
*/
public String getDisclaimer() {
return disclaimer;
}
/**
* Sets the disclaimer
*
* @param disclaimer
* Disclaimer value
*/
public void setDisclaimer(final String disclaimer) {
this.disclaimer = disclaimer;
}
}
/**
* Links to potentially other systems (e.g. support, user management,
* documentation etc.).
*
*/
public static class Links implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Configuration of UI documentation links.
*
*/
public static class Documentation implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Link to root of documentation and user guides.
*/
private String root = "";
/**
* Link to documentation of deployment view.
*/
private String deploymentView = "";
/**
* Link to documentation of distribution view.
*/
private String distributionView = "";
/**
* Link to documentation of upload view.
*/
private String uploadView = "";
/**
* Link to documentation of maintenance window view.
*/
private String maintenanceWindowView = "";
/**
* Link to documentation of the user consent and confirmation flow.
*/
private String userConsentAndConfirmationGuide = "";
public String getAutoConfirmationView() {
return autoConfirmationView;
}
/**
* Link to documentation of system configuration view.
*/
private String systemConfigurationView = "";
/**
* Link to security related documentation.
*/
private String security = "";
/**
* Link to rollout related documentation.
*/
private String rollout = "";
/**
* Link to target filter view.
*/
private String targetfilterView = "";
/**
* Link to documentation of rollout view.
*/
private String rolloutView = "";
/**
* Link to documentation of auto confirmation view.
*/
private String autoConfirmationView = "";
/**
* Link to documentation of state machine
*/
private String provisioningStateMachine = "";
/**
* Link to documentation of distribution set invalidation
*/
private String distributionSetInvalidation = "";
/**
* @return Link to documentation of deployment view
*/
public String getDeploymentView() {
return deploymentView;
}
public String getDistributionView() {
return distributionView;
}
/**
* @return Link to documentation of rollout view
*/
public String getRolloutView() {
return rolloutView;
}
/**
* @return Link to documentation of root
*/
public String getRoot() {
return root;
}
/**
* @return Link to documentation of security
*/
public String getSecurity() {
return security;
}
/**
* @return Link to documentation of rollout
*/
public String getRollout() {
return rollout;
}
/**
* @return Link to documentation of system config
*/
public String getSystemConfigurationView() {
return systemConfigurationView;
}
/**
* @return Link to documentation of target filter
*/
public String getTargetfilterView() {
return targetfilterView;
}
public String getUploadView() {
return uploadView;
}
/**
* @return Link to documentation of maintenance window
*/
public String getMaintenanceWindowView() {
return maintenanceWindowView;
}
/**
* @return Link to documentation of the user consent and confirmation flow.
*/
public String getUserConsentAndConfirmationGuide() {
return userConsentAndConfirmationGuide;
}
/**
* @return Link to documentation of provisioning state machine
*/
public String getProvisioningStateMachine() {
return provisioningStateMachine;
}
/**
* @return Link to documentation of distribution set invalidation
*/
public String getDistributionSetInvalidation() {
return distributionSetInvalidation;
}
public void setDeploymentView(final String deploymentView) {
this.deploymentView = deploymentView;
}
public void setDistributionView(final String distributionView) {
this.distributionView = distributionView;
}
public void setRolloutView(final String rolloutView) {
this.rolloutView = rolloutView;
}
/**
* Sets the root documentation link
*
* @param root
* link
*/
public void setRoot(final String root) {
this.root = root;
}
/**
* Sets the security documentation link
*
* @param security
* link
*/
public void setSecurity(final String security) {
this.security = security;
}
/**
* Sets the rollout documentation link
*
* @param rollout
* link
*/
public void setRollout(final String rollout) {
this.rollout = rollout;
}
public void setSystemConfigurationView(final String systemConfigurationView) {
this.systemConfigurationView = systemConfigurationView;
}
public void setTargetfilterView(final String targetfilterView) {
this.targetfilterView = targetfilterView;
}
public void setUploadView(final String uploadView) {
this.uploadView = uploadView;
}
public void setMaintenanceWindowView(final String maintenanceWindowView) {
this.maintenanceWindowView = maintenanceWindowView;
}
public void setUserConsentAndConfirmationGuide(final String userConsentAndConfirmationGuide) {
this.userConsentAndConfirmationGuide = userConsentAndConfirmationGuide;
}
public void setProvisioningStateMachine(final String provisioningStateMachine) {
this.provisioningStateMachine = provisioningStateMachine;
}
/**
* Sets the link to the distribution set invalidation documentation
*
* @param distributionSetInvalidation
* Link
*/
public void setDistributionSetInvalidation(String distributionSetInvalidation) {
this.distributionSetInvalidation = distributionSetInvalidation;
}
}
private final Documentation documentation = new Documentation();
/**
* Link to product support.
*/
private String support = "";
/**
* Link to request a system account, access.
*/
private String requestAccount = "";
/**
* Link to user management.
*/
private String userManagement = "";
/**
* @return Link to documentation
*/
public Documentation getDocumentation() {
return documentation;
}
/**
* @return Link to request a system account, access
*/
public String getRequestAccount() {
return requestAccount;
}
/**
* @return Link to product support
*/
public String getSupport() {
return support;
}
/**
* @return Link to user management
*/
public String getUserManagement() {
return userManagement;
}
/**
* Sets the link to request a system account, access
*
* @param requestAccount
* Link
*/
public void setRequestAccount(final String requestAccount) {
this.requestAccount = requestAccount;
}
/**
* Sets the link to product support
*
* @param support
* Link
*/
public void setSupport(final String support) {
this.support = support;
}
/**
* Sets the link to user management
*
* @param userManagement
* Link
*/
public void setUserManagement(final String userManagement) {
this.userManagement = userManagement;
}
}
/**
* Configuration of the UI event bus.
*/
public static class Event implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
* Configuration of the UI push.
*
*/
public static class Push implements Serializable {
private static final long serialVersionUID = 1L;
/**
* The delay for the ui event forwarding.
*/
private long delay = TimeUnit.SECONDS.toMillis(2);
public long getDelay() {
return delay;
}
public void setDelay(final long delay) {
this.delay = delay;
}
}
private final Push push = new Push();
public Push getPush() {
return push;
}
}
public static class Notification implements Serializable {
private String text = "";
public String getText() {
return text;
}
public void setText(final String text) {
this.text = text;
}
}
/**
* @return Demo account details
*/
public Demo getDemo() {
return demo;
}
/**
* @return Document links
*/
public Links getLinks() {
return links;
}
/**
* @return Events
*/
public Event getEvent() {
return event;
}
/**
* @return Localization
*/
public Localization getLocalization() {
return localization;
}
public Notification getNotification() {
return notification;
}
}

View File

@@ -1,320 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts;
import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.details.ArtifactDetailsGridLayoutUiState;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadId;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.VaadinSessionScope;
/**
* User status of Artifact upload.
*/
@VaadinSessionScope
@SpringComponent
public class ArtifactUploadState implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(ArtifactUploadState.class);
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
private final GridLayoutUiState smGridLayoutUiState;
private final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState;
private boolean statusPopupMinimized;
/**
* Map that holds all files that were selected for upload. They remain in
* the list even if upload fails, succeeds or is aborted by the user.
*/
private Map<FileUploadId, FileUploadProgress> overallFilesInUploadProcess;
/**
* Constructor for ArtifactUploadState
*/
public ArtifactUploadState() {
this.smTypeFilterLayoutUiState = new TypeFilterLayoutUiState();
this.smGridLayoutUiState = new GridLayoutUiState();
this.artifactDetailsGridLayoutUiState = new ArtifactDetailsGridLayoutUiState();
}
/**
* Minimize or maximize the status popup view
*
* @param statusPopupMinimized
* boolean
*/
public void setStatusPopupMinimized(final boolean statusPopupMinimized) {
this.statusPopupMinimized = statusPopupMinimized;
}
/**
* Checks if the status popup view is in minimized state
*
* @return boolean
*/
public boolean isStatusPopupMinimized() {
return statusPopupMinimized;
}
/**
* Get the Software module type filter UI state
*
* @return TypeFilterLayoutUiState
*/
public TypeFilterLayoutUiState getSmTypeFilterLayoutUiState() {
return smTypeFilterLayoutUiState;
}
/**
* Get the Software module grid UI state
*
* @return GridLayoutUiState
*/
public GridLayoutUiState getSmGridLayoutUiState() {
return smGridLayoutUiState;
}
/**
* Get the Artifact details grid UI state
*
* @return ArtifactDetailsGridLayoutUiState
*/
public ArtifactDetailsGridLayoutUiState getArtifactDetailsGridLayoutUiState() {
return artifactDetailsGridLayoutUiState;
}
/**
* Remove all the files from the upload process list
*
* @param filesToRemove
* Collection of fie upload ID
*/
public void removeFilesFromOverallUploadProcessList(final Collection<FileUploadId> filesToRemove) {
getOverallFilesInUploadProcessMap().keySet().removeAll(filesToRemove);
}
/**
* Get all the IDs of uploaded files from the upload process
*
* @return List of IDs of uploaded files
*/
public Set<FileUploadId> getAllFileUploadIdsFromOverallUploadProcessList() {
return Collections.unmodifiableSet(getOverallFilesInUploadProcessMap().keySet());
}
/**
* Get file upload progress values from process list
*
* @return List of FileUploadProgress
*/
public Collection<FileUploadProgress> getAllFileUploadProgressValuesFromOverallUploadProcessList() {
return Collections.unmodifiableCollection(getOverallFilesInUploadProcessMap().values());
}
/**
* Get all the IDs of files from the failed upload
*
* @return List of IDs of uploaded files
*/
public Set<FileUploadId> getFilesInFailedState() {
return Collections.unmodifiableSet(getFailedUploads());
}
/**
* Get upload progress of the file
*
* @param fileUploadId
* FileUploadId
*
* @return FileUploadProgress
*/
public FileUploadProgress getFileUploadProgress(final FileUploadId fileUploadId) {
return getOverallFilesInUploadProcessMap().get(fileUploadId);
}
/**
* Get all files that were selected for upload
*
* @param fileUploadId
* FileUploadId
* @param fileUploadProgress
* FileUploadProgress
*/
public void updateFileUploadProgress(final FileUploadId fileUploadId, final FileUploadProgress fileUploadProgress) {
getOverallFilesInUploadProcessMap().put(fileUploadId, fileUploadProgress);
}
/**
* Check upload state of the file
*
* @param fileUploadId
* FileUploadId
*
* @return boolean
*/
public boolean isFileInUploadState(final FileUploadId fileUploadId) {
return getOverallFilesInUploadProcessMap().containsKey(fileUploadId);
}
/**
* Check upload state of the file link to the related software module
*
* @param filename
* Name of the file
*
* @param softwareModule
* the {@link SoftwareModule} for which the file is uploaded
*
* @return boolean
*/
public boolean isFileInUploadState(final String filename, final SoftwareModule softwareModule) {
return isFileInUploadState(new FileUploadId(filename, softwareModule));
}
/**
* Check if at least one file upload is in progress
*
* @return boolean
*/
public boolean isAtLeastOneUploadInProgress() {
return getInProgressCount() > 0;
}
/**
* Check if all file uploads are finished
*
* @return boolean
*/
public boolean areAllUploadsFinished() {
return getInProgressCount() == 0;
}
private int getInProgressCount() {
final int succeededUploadCount = getSucceededUploads().size();
final int failedUploadCount = getFailedUploads().size();
final int overallUploadCount = getOverallFilesInUploadProcessMap().size();
final int inProgressCount = overallUploadCount - failedUploadCount - succeededUploadCount;
assertFileStateConsistency(inProgressCount, overallUploadCount, succeededUploadCount, failedUploadCount);
return inProgressCount;
}
@SuppressWarnings("java:S2629") // error shall be enable almost every time and evaluation is light
private static void assertFileStateConsistency(final int inProgressCount, final int overallUploadCount,
final int succeededUploadCount, final int failedUploadCount) {
if (inProgressCount < 0) {
LOG.error("IllegalState: \n{}",
getStateListLogMessage(overallUploadCount, succeededUploadCount, failedUploadCount));
}
}
private static String getStateListLogMessage(final int overallUploadCount, final int succeededUploadCount,
final int failedUploadCount) {
final StringBuilder buffer = new StringBuilder();
buffer.append("Overall uploads: " + overallUploadCount);
buffer.append("| succeeded uploads: " + succeededUploadCount);
buffer.append("| Failed Uploads: " + failedUploadCount);
return buffer.toString();
}
/**
* Removes all of the data from this Upload process collection
*/
public void clearFileStates() {
getOverallFilesInUploadProcessMap().clear();
}
/**
* Clears all temp data collected while uploading files.
*/
public void clearUploadTempData() {
LOG.debug("Cleaning up temp data...");
// delete file system zombies
for (final FileUploadProgress fileUploadProgress : getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
if (StringUtils.hasText(fileUploadProgress.getFilePath())) {
final boolean deleted = FileUtils.deleteQuietly(new File(fileUploadProgress.getFilePath()));
if (!deleted) {
LOG.warn("TempFile was not deleted: {}", fileUploadProgress.getFilePath());
}
}
}
clearFileStates();
}
/**
* Checks if an upload is in progress for the given Software Module
*
* @param softwareModuleId
* id of the software module
*
* @return boolean
*/
public boolean isUploadInProgressForSelectedSoftwareModule(final Long softwareModuleId) {
for (final FileUploadId fileUploadId : getAllFileUploadIdsFromOverallUploadProcessList()) {
if (fileUploadId.getSoftwareModuleId().equals(softwareModuleId)) {
return true;
}
}
return false;
}
private Map<FileUploadId, FileUploadProgress> getOverallFilesInUploadProcessMap() {
if (overallFilesInUploadProcess == null) {
overallFilesInUploadProcess = Maps.newConcurrentMap();
}
return overallFilesInUploadProcess;
}
private Set<FileUploadId> getFailedUploads() {
final Collection<FileUploadProgress> allFileUploadProgressObjects = getOverallFilesInUploadProcessMap()
.values();
final Set<FileUploadId> failedFileUploads = Sets.newHashSet();
for (final FileUploadProgress fileUploadProgress : allFileUploadProgressObjects) {
if (fileUploadProgress.getFileUploadStatus() == FileUploadStatus.UPLOAD_FAILED) {
failedFileUploads.add(fileUploadProgress.getFileUploadId());
}
}
return failedFileUploads;
}
private Set<FileUploadId> getSucceededUploads() {
final Collection<FileUploadProgress> allFileUploadProgressObjects = getOverallFilesInUploadProcessMap()
.values();
final Set<FileUploadId> succeededFileUploads = Sets.newHashSet();
for (final FileUploadProgress fileUploadProgress : allFileUploadProgressObjects) {
if (fileUploadProgress.getFileUploadStatus() == FileUploadStatus.UPLOAD_SUCCESSFUL) {
succeededFileUploads.add(fileUploadProgress.getFileUploadId());
}
}
return succeededFileUploads;
}
}

View File

@@ -1,335 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts;
import static org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus.UPLOAD_STARTED;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;
import javax.servlet.MultipartConfigElement;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.artifacts.details.ArtifactDetailsGridLayout;
import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleGridLayout;
import org.eclipse.hawkbit.ui.artifacts.smtype.filter.SMTypeFilterLayout;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.event.EventViewAware;
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutResizeListener;
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutResizeListener.ResizeHandler;
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutVisibilityListener;
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutVisibilityListener.VisibilityHandler;
import org.eclipse.hawkbit.ui.menu.DashboardEvent;
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.navigator.ViewBeforeLeaveEvent;
import com.vaadin.server.Page;
import com.vaadin.server.Page.BrowserWindowResizeEvent;
import com.vaadin.server.Page.BrowserWindowResizeListener;
import com.vaadin.spring.annotation.SpringView;
import com.vaadin.spring.annotation.UIScope;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.UI;
/**
* Display artifacts upload view.
*/
@UIScope
@SpringView(name = UploadArtifactView.VIEW_NAME, ui = AbstractHawkbitUI.class)
public class UploadArtifactView extends AbstractEventListenersAwareView implements BrowserWindowResizeListener {
private static final long serialVersionUID = 1L;
public static final String VIEW_NAME = "spUpload";
private final SpPermissionChecker permChecker;
private final ArtifactUploadState artifactUploadState;
private final SMTypeFilterLayout smTypeFilterLayout;
private final SoftwareModuleGridLayout smGridLayout;
private final ArtifactDetailsGridLayout artifactDetailsGridLayout;
private final VaadinMessageSource i18n;
private final DashboardMenu dashboardMenu;
private HorizontalLayout mainLayout;
private final transient LayoutVisibilityListener layoutVisibilityListener;
private final transient LayoutResizeListener layoutResizeListener;
@Autowired
UploadArtifactView(final UIEventBus eventBus, final SpPermissionChecker permChecker, final VaadinMessageSource i18n,
final UINotification uiNotification, final ArtifactUploadState artifactUploadState,
final EntityFactory entityFactory, final SoftwareModuleManagement softwareModuleManagement,
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
final MultipartConfigElement multipartConfigElement, final ArtifactManagement artifactManagement,
final DashboardMenu dashboardMenu) {
this.permChecker = permChecker;
this.artifactUploadState = artifactUploadState;
this.i18n = i18n;
this.dashboardMenu = dashboardMenu;
final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus,
uiNotification, permChecker);
if (permChecker.hasReadRepositoryPermission()) {
this.smTypeFilterLayout = new SMTypeFilterLayout(uiDependencies, softwareModuleTypeManagement,
artifactUploadState.getSmTypeFilterLayoutUiState(), EventView.UPLOAD);
this.smGridLayout = new SoftwareModuleGridLayout(uiDependencies, softwareModuleManagement,
softwareModuleTypeManagement, artifactUploadState.getSmTypeFilterLayoutUiState(),
artifactUploadState.getSmGridLayoutUiState());
this.artifactDetailsGridLayout = new ArtifactDetailsGridLayout(uiDependencies, artifactUploadState,
artifactUploadState.getArtifactDetailsGridLayoutUiState(), artifactManagement,
softwareModuleManagement, multipartConfigElement);
addEventAwareLayouts(Arrays.asList(smTypeFilterLayout, smGridLayout, artifactDetailsGridLayout));
final Map<EventLayout, VisibilityHandler> layoutVisibilityHandlers = new EnumMap<>(EventLayout.class);
layoutVisibilityHandlers.put(EventLayout.SM_TYPE_FILTER,
new VisibilityHandler(this::showSmTypeLayout, this::hideSmTypeLayout));
this.layoutVisibilityListener = new LayoutVisibilityListener(eventBus, new EventViewAware(EventView.UPLOAD),
layoutVisibilityHandlers);
final Map<EventLayout, ResizeHandler> layoutResizeHandlers = new EnumMap<>(EventLayout.class);
layoutResizeHandlers.put(EventLayout.SM_LIST,
new ResizeHandler(this::maximizeSmGridLayout, this::minimizeSmGridLayout));
layoutResizeHandlers.put(EventLayout.ARTIFACT_LIST,
new ResizeHandler(this::maximizeArtifactGridLayout, this::minimizeArtifactGridLayout));
this.layoutResizeListener = new LayoutResizeListener(eventBus, new EventViewAware(EventView.UPLOAD),
layoutResizeHandlers);
} else {
this.smTypeFilterLayout = null;
this.smGridLayout = null;
this.artifactDetailsGridLayout = null;
this.layoutVisibilityListener = null;
this.layoutResizeListener = null;
}
}
@Override
protected void init() {
if (permChecker.hasReadRepositoryPermission()) {
super.init();
Page.getCurrent().addBrowserWindowResizeListener(this);
}
}
@Override
protected void buildLayout() {
setMargin(false);
setSpacing(false);
setSizeFull();
createMainLayout();
addComponent(mainLayout);
setExpandRatio(mainLayout, 1.0F);
}
private void createMainLayout() {
mainLayout = new HorizontalLayout();
mainLayout.setSizeFull();
mainLayout.setMargin(false);
mainLayout.setSpacing(true);
mainLayout.addComponent(smTypeFilterLayout);
mainLayout.addComponent(smGridLayout);
mainLayout.addComponent(artifactDetailsGridLayout);
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
mainLayout.setExpandRatio(smGridLayout, 0.5F);
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
}
@Override
protected void restoreState() {
if (permChecker.hasReadRepositoryPermission()) {
restoreSmWidgetsState();
restoreArtifactWidgetsState();
}
super.restoreState();
}
private void restoreSmWidgetsState() {
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()
|| artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
hideSmTypeLayout();
} else {
showSmTypeLayout();
}
if (artifactUploadState.getSmGridLayoutUiState().isMaximized()) {
maximizeSmGridLayout();
}
}
private void restoreArtifactWidgetsState() {
if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
maximizeArtifactGridLayout();
}
}
private void showSmTypeLayout() {
smTypeFilterLayout.setVisible(true);
smGridLayout.hideSmTypeHeaderIcon();
}
private void hideSmTypeLayout() {
smTypeFilterLayout.setVisible(false);
smGridLayout.showSmTypeHeaderIcon();
}
private void maximizeSmGridLayout() {
artifactDetailsGridLayout.setVisible(false);
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
mainLayout.setExpandRatio(smGridLayout, 1.0F);
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0F);
smGridLayout.maximize();
}
private void minimizeSmGridLayout() {
artifactDetailsGridLayout.setVisible(true);
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
mainLayout.setExpandRatio(smGridLayout, 0.5F);
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
smGridLayout.minimize();
}
private void maximizeArtifactGridLayout() {
smTypeFilterLayout.setVisible(false);
smGridLayout.setVisible(false);
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
mainLayout.setExpandRatio(smGridLayout, 0F);
mainLayout.setExpandRatio(artifactDetailsGridLayout, 1.0F);
artifactDetailsGridLayout.maximize();
}
private void minimizeArtifactGridLayout() {
if (!artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
smTypeFilterLayout.setVisible(true);
}
smGridLayout.setVisible(true);
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
mainLayout.setExpandRatio(smGridLayout, 0.5F);
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
artifactDetailsGridLayout.minimize();
}
/**
* Show or hide the filter button based on the event width
*
* @param event
* BrowserWindowResizeEvent
*/
@Override
public void browserWindowResized(final BrowserWindowResizeEvent event) {
showOrHideFilterButtons(event.getWidth());
}
private void showOrHideFilterButtons(final int browserWidth) {
if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
return;
}
if (browserWidth < SPUIDefinitions.REQ_MIN_BROWSER_WIDTH) {
if (!artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
hideSmTypeLayout();
}
} else {
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
showSmTypeLayout();
}
}
}
@Override
public String getViewName() {
return UploadArtifactView.VIEW_NAME;
}
@Override
protected void subscribeListeners() {
if (permChecker.hasReadRepositoryPermission()) {
layoutVisibilityListener.subscribe();
layoutResizeListener.subscribe();
}
super.subscribeListeners();
}
@Override
protected void unsubscribeListeners() {
if (permChecker.hasReadRepositoryPermission()) {
layoutVisibilityListener.unsubscribe();
layoutResizeListener.unsubscribe();
}
super.unsubscribeListeners();
}
@Override
public void beforeLeave(final ViewBeforeLeaveEvent event) {
if (isAnyUploadInUploadQueue()) {
final ConfirmationDialog confirmDeleteDialog = ConfirmationDialog
.newBuilder(i18n, UIComponentIdProvider.UPLOAD_QUEUE_CLEAR_CONFIRMATION_DIALOG)
.caption(i18n.getMessage(UIMessageIdProvider.CAPTION_CLEAR_FILE_UPLOAD_QUEUE))
.question(i18n.getMessage(UIMessageIdProvider.MESSAGE_CLEAR_FILE_UPLOAD_QUEUE))
.onSaveOrUpdate(() -> {
// Clear all queued file uploads
artifactUploadState.clearFileStates();
super.beforeLeave(event);
}).onCancel(() -> {
// Send a PostViewChangeEvent to the DashboardMenu
// as if the navigation actually
// happened to prevent the DashboardMenu navigation
// from getting stuck
final DashboardMenuItem dashboardMenuItem = dashboardMenu.getByViewName(VIEW_NAME);
dashboardMenu.postViewChange(DashboardEvent.createPostViewChangeEvent(dashboardMenuItem));
}).build();
UI.getCurrent().addWindow(confirmDeleteDialog.getWindow());
confirmDeleteDialog.getWindow().bringToFront();
} else {
super.beforeLeave(event);
}
}
private boolean isAnyUploadInUploadQueue() {
return artifactUploadState.getAllFileUploadProgressValuesFromOverallUploadProcessList().stream()
.map(FileUploadProgress::getFileUploadStatus)
.anyMatch(fileUploadStatus -> fileUploadStatus == UPLOAD_STARTED);
}
}

View File

@@ -1,66 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.ui.menu.AbstractDashboardMenuItemNotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.server.Resource;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.UIScope;
/**
* Display artifacts upload view menu item.
*
*
*/
@SpringComponent
@UIScope
@Order(500)
public class UploadArtifactViewMenuItem extends AbstractDashboardMenuItemNotification {
private static final long serialVersionUID = 1L;
@Autowired
UploadArtifactViewMenuItem(final VaadinMessageSource i18n) {
super(i18n);
}
@Override
public String getViewName() {
return UploadArtifactView.VIEW_NAME;
}
@Override
public Resource getDashboardIcon() {
return VaadinIcons.UPLOAD;
}
@Override
public String getDashboardCaption() {
return i18n.getMessage("dashboard.upload.caption");
}
@Override
public String getDashboardCaptionLong() {
return i18n.getMessage("dashboard.upload.caption-long");
}
@Override
public List<String> getPermissions() {
return Arrays.asList(SpPermission.READ_REPOSITORY);
}
}

View File

@@ -1,252 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.details;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
import org.eclipse.hawkbit.ui.common.data.mappers.ArtifactToProxyArtifactMapper;
import org.eclipse.hawkbit.ui.common.data.providers.ArtifactDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyArtifact;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.FilterType;
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
import org.eclipse.hawkbit.ui.common.grid.support.FilterSupport;
import org.eclipse.hawkbit.ui.common.grid.support.MasterEntitySupport;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.server.FileDownloader;
import com.vaadin.server.StreamResource;
import com.vaadin.ui.Button;
import com.vaadin.ui.UI;
/**
* Artifact Details grid which is shown on the Upload View.
*/
public class ArtifactDetailsGrid extends AbstractGrid<ProxyArtifact, Long> {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(ArtifactDetailsGrid.class);
private static final String ARTIFACT_NAME_ID = "artifactName";
private static final String ARTIFACT_SIZE_ID = "artifactSize";
private static final String ARTIFACT_MODIFIED_DATE_ID = "artifactModifiedDate";
private static final String ARTIFACT_SHA1_ID = "artifactSha1";
private static final String ARTIFACT_MD5_ID = "artifactMd5";
private static final String ARTIFACT_SHA256_ID = "artifactSha256";
private static final String ARTIFACT_DOWNLOAD_BUTTON_ID = "artifactDownloadButton";
private static final String ARTIFACT_DELETE_BUTTON_ID = "artifactDeleteButton";
private final UINotification notification;
private final transient ArtifactManagement artifactManagement;
private final transient DeleteSupport<ProxyArtifact> artifactDeleteSupport;
private final transient MasterEntitySupport<ProxySoftwareModule> masterEntitySupport;
private boolean artifactsEncrypted;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param artifactManagement
* ArtifactManagement
*/
public ArtifactDetailsGrid(final CommonUiDependencies uiDependencies, final ArtifactManagement artifactManagement) {
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
this.notification = uiDependencies.getUiNotification();
this.artifactManagement = artifactManagement;
this.artifactDeleteSupport = new DeleteSupport<>(this, i18n, notification, "artifact.details.header",
"caption.artifacts", ProxyArtifact::getFilename, this::artifactsDeletionCallback,
UIComponentIdProvider.ARTIFACT_DELETE_CONFIRMATION_DIALOG);
setFilterSupport(
new FilterSupport<>(new ArtifactDataProvider(artifactManagement, new ArtifactToProxyArtifactMapper())));
initFilterMappings();
this.masterEntitySupport = new MasterEntitySupport<>(getFilterSupport(), null,
sm -> artifactsEncrypted = sm != null && sm.isEncrypted());
init();
}
private void initFilterMappings() {
getFilterSupport().<Long> addMapping(FilterType.MASTER,
(filter, masterFilter) -> getFilterSupport().setFilter(masterFilter));
}
/**
* Initial method of grid and set style name
*/
@Override
public void init() {
super.init();
addStyleName("grid-row-border");
}
private boolean artifactsDeletionCallback(final Collection<ProxyArtifact> artifactsToBeDeleted) {
final Collection<Long> artifactToBeDeletedIds = artifactsToBeDeleted.stream()
.map(ProxyIdentifiableEntity::getId).collect(Collectors.toList());
artifactToBeDeletedIds.forEach(artifactManagement::delete);
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, masterEntitySupport.getMasterId()));
return true;
}
/**
* @return ID for artifact details table
*/
@Override
public String getGridId() {
return UIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE;
}
/**
* setting up the columns with their required definition
*/
@Override
public void addColumns() {
addFilenameColumn().setExpandRatio(2);
addSizeColumn();
addModifiedDateColumn();
GridComponentBuilder.joinToActionColumn(i18n, getDefaultHeaderRow(),
Arrays.asList(addDownloadColumn(), addDeleteColumn()));
}
private Column<ProxyArtifact, String> addFilenameColumn() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getFilename).setId(ARTIFACT_NAME_ID)
.setCaption(i18n.getMessage("artifact.filename.caption"));
}
private Column<ProxyArtifact, Long> addSizeColumn() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSize).setId(ARTIFACT_SIZE_ID)
.setCaption(i18n.getMessage("artifact.filesize.bytes.caption"));
}
protected Column<ProxyArtifact, String> addModifiedDateColumn() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getModifiedDate).setId(ARTIFACT_MODIFIED_DATE_ID)
.setCaption(i18n.getMessage("upload.last.modified.date"));
}
private Column<ProxyArtifact, Button> addDownloadColumn() {
return GridComponentBuilder.addIconColumn(this, this::buildDownloadButton, ARTIFACT_DOWNLOAD_BUTTON_ID,
i18n.getMessage("header.action.download"));
}
private Button buildDownloadButton(final ProxyArtifact artifact) {
final Button downloadButton = GridComponentBuilder.buildActionButton(i18n, clickEvent -> {
}, VaadinIcons.DOWNLOAD, UIMessageIdProvider.TOOLTIP_ARTIFACT_DOWNLOAD,
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
UIComponentIdProvider.ARTIFACT_FILE_DOWNLOAD_ICON + "." + artifact.getId(),
permissionChecker.hasDownloadRepositoryPermission());
attachFileDownloader(artifact, downloadButton);
return downloadButton;
}
private void attachFileDownloader(final ProxyArtifact artifact, final Button downloadButton) {
final StreamResource artifactStreamResource = new StreamResource(() -> artifactManagement
.loadArtifactBinary(artifact.getSha1Hash(), masterEntitySupport.getMasterId(), artifactsEncrypted)
.map(DbArtifact::getFileInputStream).orElse(null), artifact.getFilename());
final FileDownloader fileDownloader = new FileDownloader(artifactStreamResource);
fileDownloader.setErrorHandler(event -> {
LOG.error("Download failed for artifact with id {}, filename {}", artifact.getId(), artifact.getFilename(),
event.getThrowable());
notification.displayValidationError(i18n.getMessage(UIMessageIdProvider.ARTIFACT_DOWNLOAD_FAILURE_MSG));
UI.getCurrent().access(() -> {
// give error details extractors a chance to process specific
// error
throw new DownloadException(event.getThrowable());
});
});
fileDownloader.extend(downloadButton);
}
private Column<ProxyArtifact, Button> addDeleteColumn() {
return GridComponentBuilder.addDeleteColumn(this, i18n, ARTIFACT_DELETE_BUTTON_ID, artifactDeleteSupport,
UIComponentIdProvider.ARTIFACT_DELET_ICON, e -> permissionChecker.hasDeleteRepositoryPermission());
}
@Override
protected void addMaxColumns() {
addFilenameColumn().setExpandRatio(2);
addSizeColumn();
addSha1Column();
addMd5Column();
addSha256Column();
addModifiedDateColumn();
GridComponentBuilder.joinToActionColumn(i18n, getDefaultHeaderRow(),
Arrays.asList(addDownloadColumn(), addDeleteColumn()));
getColumns().forEach(column -> column.setHidable(true));
}
private Column<ProxyArtifact, String> addSha1Column() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha1Hash).setId(ARTIFACT_SHA1_ID)
.setCaption(i18n.getMessage("upload.sha1"));
}
private Column<ProxyArtifact, String> addMd5Column() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getMd5Hash).setId(ARTIFACT_MD5_ID)
.setCaption(i18n.getMessage("upload.md5"));
}
private Column<ProxyArtifact, String> addSha256Column() {
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha256Hash).setId(ARTIFACT_SHA256_ID)
.setCaption(i18n.getMessage("upload.sha256"));
}
/**
* @return software module entity
*/
public MasterEntitySupport<ProxySoftwareModule> getMasterEntitySupport() {
return masterEntitySupport;
}
private static class DownloadException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DownloadException(final Throwable cause) {
super(cause);
}
}
}

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.details;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.CommandTopics;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.event.LayoutResizeEventPayload;
import org.eclipse.hawkbit.ui.common.event.LayoutResizeEventPayload.ResizeType;
import org.eclipse.hawkbit.ui.common.grid.header.AbstractMasterAwareGridHeader;
import org.eclipse.hawkbit.ui.common.grid.header.support.ResizeHeaderSupport;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
/**
* Header for ArtifactDetails with maximize-support.
*/
public class ArtifactDetailsGridHeader extends AbstractMasterAwareGridHeader<ProxySoftwareModule> {
private static final long serialVersionUID = 1L;
private final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState;
private final transient ResizeHeaderSupport resizeHeaderSupport;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param artifactDetailsGridLayoutUiState
* ArtifactDetailsGridLayoutUiState
*/
public ArtifactDetailsGridHeader(final CommonUiDependencies uiDependencies,
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState) {
super(uiDependencies.getI18n(), uiDependencies.getPermChecker(), uiDependencies.getEventBus());
this.artifactDetailsGridLayoutUiState = artifactDetailsGridLayoutUiState;
this.resizeHeaderSupport = new ResizeHeaderSupport(i18n, SPUIDefinitions.EXPAND_ARTIFACT_DETAILS,
this::maximizeTable, this::minimizeTable, this::onLoadIsTableMaximized);
addHeaderSupport(resizeHeaderSupport);
buildHeader();
}
@Override
protected String getEntityDetailsCaptionMsgKey() {
return UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS;
}
@Override
protected String getMasterEntityDetailsCaptionId() {
return UIComponentIdProvider.ARTIFACT_DETAILS_HEADER_LABEL_ID;
}
@Override
protected String getMasterEntityName(final ProxySoftwareModule masterEntity) {
return masterEntity.getNameAndVersion();
}
@Override
protected String getEntityDetailsCaptionOfMsgKey() {
return UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS_OF;
}
private void maximizeTable() {
eventBus.publish(CommandTopics.RESIZE_LAYOUT, this,
new LayoutResizeEventPayload(ResizeType.MAXIMIZE, EventLayout.ARTIFACT_LIST, EventView.UPLOAD));
artifactDetailsGridLayoutUiState.setMaximized(true);
}
private void minimizeTable() {
eventBus.publish(CommandTopics.RESIZE_LAYOUT, this,
new LayoutResizeEventPayload(ResizeType.MINIMIZE, EventLayout.ARTIFACT_LIST, EventView.UPLOAD));
artifactDetailsGridLayoutUiState.setMaximized(false);
}
private Boolean onLoadIsTableMaximized() {
return artifactDetailsGridLayoutUiState.isMaximized();
}
}

View File

@@ -1,140 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.details;
import java.util.Arrays;
import java.util.List;
import javax.servlet.MultipartConfigElement;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
import org.eclipse.hawkbit.ui.artifacts.upload.UploadDropAreaLayout;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.layout.AbstractGridComponentLayout;
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
import org.eclipse.hawkbit.ui.common.layout.listener.GenericEventListener;
import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener;
/**
* Display the details of the artifacts for a selected software module.
*/
public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout {
private static final long serialVersionUID = 1L;
private final ArtifactDetailsGridHeader artifactDetailsHeader;
private final ArtifactDetailsGrid artifactDetailsGrid;
private final UploadDropAreaLayout uploadDropAreaLayout;
private final transient SelectionChangedListener<ProxySoftwareModule> selectionChangedListener;
private final transient GenericEventListener<FileUploadProgress> fileUploadChangedListener;
/**
* Constructor for ArtifactDetailsLayout
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param artifactUploadState
* ArtifactUploadState
* @param artifactDetailsGridLayoutUiState
* ArtifactDetailsGridLayoutUiState
* @param artifactManagement
* ArtifactManagement
* @param softwareManagement
* SoftwareModuleManagement
* @param multipartConfigElement
* MultipartConfigElement
*/
public ArtifactDetailsGridLayout(final CommonUiDependencies uiDependencies,
final ArtifactUploadState artifactUploadState,
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState,
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
final MultipartConfigElement multipartConfigElement) {
this.artifactDetailsHeader = new ArtifactDetailsGridHeader(uiDependencies, artifactDetailsGridLayoutUiState);
this.artifactDetailsGrid = new ArtifactDetailsGrid(uiDependencies, artifactManagement);
if (uiDependencies.getPermChecker().hasCreateRepositoryPermission()) {
this.uploadDropAreaLayout = new UploadDropAreaLayout(uiDependencies, artifactUploadState,
multipartConfigElement, softwareManagement, artifactManagement);
buildLayout(artifactDetailsHeader, artifactDetailsGrid, uploadDropAreaLayout);
} else {
this.uploadDropAreaLayout = null;
buildLayout(artifactDetailsHeader, artifactDetailsGrid);
}
final EventLayoutViewAware masterLayoutView = new EventLayoutViewAware(EventLayout.SM_LIST, EventView.UPLOAD);
this.selectionChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), masterLayoutView,
getMasterEntityAwareComponents());
this.fileUploadChangedListener = new GenericEventListener<>(uiDependencies.getEventBus(),
EventTopics.FILE_UPLOAD_CHANGED, this::onUploadChanged);
}
private List<MasterEntityAwareComponent<ProxySoftwareModule>> getMasterEntityAwareComponents() {
return Arrays.asList(artifactDetailsHeader, artifactDetailsGrid.getMasterEntitySupport(), uploadDropAreaLayout);
}
/**
* Checks progress on file upload
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
if (uploadDropAreaLayout != null) {
uploadDropAreaLayout.onUploadChanged(fileUploadProgress);
}
}
/**
* Maximize the artifact grid
*/
public void maximize() {
artifactDetailsGrid.createMaximizedContent();
hideDetailsLayout();
}
/**
* Minimize the artifact grid
*/
public void minimize() {
artifactDetailsGrid.createMinimizedContent();
showDetailsLayout();
}
@Override
public void restoreState() {
artifactDetailsHeader.restoreState();
if (uploadDropAreaLayout != null) {
uploadDropAreaLayout.restoreState();
}
}
@Override
public void subscribeListeners() {
selectionChangedListener.subscribe();
fileUploadChangedListener.subscribe();
}
@Override
public void unsubscribeListeners() {
selectionChangedListener.unsubscribe();
fileUploadChangedListener.unsubscribe();
}
}

View File

@@ -1,36 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.details;
import java.io.Serializable;
/**
* Display and set the current state of the artifacts detail layout
*
*/
public class ArtifactDetailsGridLayoutUiState implements Serializable {
private static final long serialVersionUID = 1L;
private boolean maximized;
/**
* @return current state artifact detail grid
*/
public boolean isMaximized() {
return maximized;
}
/**
* @param maximized set artifact detail grid to true or false
*/
public void setMaximized(final boolean maximized) {
this.maximized = maximized;
}
}

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.common.AbstractAddNamedEntityWindowController;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
import org.eclipse.hawkbit.ui.common.data.mappers.SoftwareModuleToProxyMapper;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload;
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload.SelectionChangedEventType;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* Controller for populating and saving data in Add Software Module Window.
*/
public class AddSmWindowController
extends AbstractAddNamedEntityWindowController<ProxySoftwareModule, ProxySoftwareModule, SoftwareModule> {
private final SoftwareModuleManagement smManagement;
private final SmWindowLayout layout;
private final EventView view;
private final ProxySmValidator validator;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smManagement
* SoftwareModuleManagement
* @param layout
* SoftwareModuleWindowLayout
* @param view
* EventView
*/
public AddSmWindowController(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement,
final SmWindowLayout layout, final EventView view) {
super(uiDependencies);
this.smManagement = smManagement;
this.layout = layout;
this.view = view;
this.validator = new ProxySmValidator(uiDependencies);
}
@Override
public EntityWindowLayout<ProxySoftwareModule> getLayout() {
return layout;
}
@Override
protected void adaptLayout(final ProxySoftwareModule proxyEntity) {
if (!ArtifactEncryptionService.getInstance().isEncryptionSupported()) {
layout.disableEncryptionField();
}
}
@Override
protected ProxySoftwareModule buildEntityFromProxy(final ProxySoftwareModule proxyEntity) {
// We ignore the method parameter, because we are interested in the
// empty object, that we can populate with defaults
return new ProxySoftwareModule();
}
@Override
protected SoftwareModule persistEntityInRepository(final ProxySoftwareModule entity) {
final SoftwareModuleCreate smCreate = getEntityFactory().softwareModule().create()
.type(entity.getTypeInfo().getKey()).name(entity.getName()).version(entity.getVersion())
.vendor(entity.getVendor()).description(entity.getDescription()).encrypted(entity.isEncrypted());
return smManagement.create(smCreate);
}
@Override
protected String getDisplayableName(final SoftwareModule entity) {
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
}
@Override
protected String getDisplayableNameForFailedMessage(final ProxySoftwareModule entity) {
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
return ProxySoftwareModule.class;
}
@Override
protected void selectPersistedEntity(final SoftwareModule entity) {
final ProxySoftwareModule addedItem = new SoftwareModuleToProxyMapper().map(entity);
publishSelectionEvent(new SelectionChangedEventPayload<>(SelectionChangedEventType.ENTITY_SELECTED, addedItem,
EventLayout.SM_LIST, view));
}
@Override
protected boolean isEntityValid(final ProxySoftwareModule entity) {
final String name = entity.getName();
final String version = entity.getVersion();
final Long typeId = entity.getTypeInfo().getId();
return validator.isEntityValid(entity,
() -> smManagement.getByNameAndVersionAndType(name, version, typeId).isPresent());
}
}

View File

@@ -1,49 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import java.util.function.BooleanSupplier;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.EntityValidator;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.springframework.util.StringUtils;
/**
* Validator used in SoftwareModule window controllers to validate
* {@link ProxySoftwareModule}.
*/
public class ProxySmValidator extends EntityValidator {
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
public ProxySmValidator(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
}
boolean isEntityValid(final ProxySoftwareModule entity, final BooleanSupplier duplicateCheck) {
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getVersion())
|| entity.getTypeInfo() == null) {
displayValidationError("message.error.missing.nameorversionortype");
return false;
}
if (duplicateCheck.getAsBoolean()) {
displayValidationError("message.duplicate.softwaremodule", entity.getName(), entity.getVersion());
return false;
}
return true;
}
}

View File

@@ -1,54 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import java.util.function.BooleanSupplier;
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataAddUpdateWindowLayout;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.VerticalLayout;
/**
* Class for sm metadata add/update window layout.
*/
public class SmMetaDataAddUpdateWindowLayout extends MetaDataAddUpdateWindowLayout {
protected final CheckBox isVisibleForTarget;
/**
* Constructor for AbstractTagWindowLayout
*
* @param i18n
* VaadinMessageSource
* @param hasMetadataChangePermission
* checks the permission allowing to change metadata entities
*/
public SmMetaDataAddUpdateWindowLayout(final VaadinMessageSource i18n,
final BooleanSupplier hasMetadataChangePermission) {
super(i18n, hasMetadataChangePermission);
this.isVisibleForTarget = metaDataComponentBuilder.createVisibleForTargetsField(binder);
}
@Override
protected VerticalLayout getMetadataAddUpdateLayout() {
final VerticalLayout addUpdateLayout = super.getMetadataAddUpdateLayout();
addUpdateLayout.addComponent(isVisibleForTarget);
return addUpdateLayout;
}
@Override
protected void disableMetadataInputComponents() {
super.disableMetadataInputComponents();
isVisibleForTarget.setEnabled(false);
}
}

View File

@@ -1,69 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyMetaData;
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractMetaDataWindowBuilder;
import com.vaadin.ui.Window;
/**
* Builder for Software module meta data windows
*/
public class SmMetaDataWindowBuilder extends AbstractMetaDataWindowBuilder<Long> {
private final SoftwareModuleManagement smManagement;
/**
* Constructor for SmMetaDataWindowBuilder
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smManagement
* SoftwareModuleManagement
*/
public SmMetaDataWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement) {
super(uiDependencies);
this.smManagement = smManagement;
}
/**
* Get software module window without proxy meta data
*
* @param smId
* software module ID
* @param name
* Selected entity name
*
* @return software module window
*/
public Window getWindowForShowSmMetaData(final Long smId, final String name) {
return getWindowForShowSmMetaData(smId, name, null);
}
/**
* Get software module window with proxy meta data
*
* @param smId
* software module ID
* @param name
* Selected entity name
* @param proxyMetaData
* ProxyMetaData
*
* @return software module window
*/
public Window getWindowForShowSmMetaData(final Long smId, final String name, final ProxyMetaData proxyMetaData) {
return getWindowForShowMetaData(new SmMetaDataWindowLayout(uiDependencies, smManagement), smId, name, proxyMetaData);
}
}

View File

@@ -1,130 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.MetaData;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.providers.SmMetaDataDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyMetaData;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractMetaDataWindowLayout;
import org.eclipse.hawkbit.ui.common.detailslayout.AddMetaDataWindowController;
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataAddUpdateWindowLayout;
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataWindowGrid;
import org.eclipse.hawkbit.ui.common.detailslayout.UpdateMetaDataWindowController;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
/**
* Class for metadata add/update window layout.
*/
public class SmMetaDataWindowLayout extends AbstractMetaDataWindowLayout<Long> {
private static final long serialVersionUID = 1L;
private final transient SoftwareModuleManagement smManagement;
private final MetaDataWindowGrid<Long> smMetaDataWindowGrid;
private final transient SmMetaDataAddUpdateWindowLayout smMetaDataAddUpdateWindowLayout;
private final transient AddMetaDataWindowController addSmMetaDataWindowController;
private final transient UpdateMetaDataWindowController updateSmMetaDataWindowController;
/**
* Constructor for AbstractTagWindowLayout
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smManagement
* SoftwareModuleManagement
*/
public SmMetaDataWindowLayout(final CommonUiDependencies uiDependencies,
final SoftwareModuleManagement smManagement) {
super(uiDependencies);
this.smManagement = smManagement;
this.smMetaDataWindowGrid = new MetaDataWindowGrid<>(uiDependencies, new SmMetaDataDataProvider(smManagement),
this::hasMetadataChangePermission, this::deleteMetaData);
this.smMetaDataAddUpdateWindowLayout = new SmMetaDataAddUpdateWindowLayout(i18n,this::hasMetadataChangePermission);
this.addSmMetaDataWindowController = new AddMetaDataWindowController(uiDependencies,
smMetaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate);
this.updateSmMetaDataWindowController = new UpdateMetaDataWindowController(uiDependencies,
smMetaDataAddUpdateWindowLayout, this::updateMetaData, this::isDuplicate);
buildLayout();
addGridSelectionListener();
}
@Override
protected String getEntityType() {
return i18n.getMessage("caption.software.module");
}
@Override
protected MetaData doCreateMetaData(final ProxyMetaData entity) {
return smManagement
.createMetaData(uiDependencies.getEntityFactory().softwareModuleMetadata().create(masterEntityFilter)
.key(entity.getKey()).value(entity.getValue()).targetVisible(entity.isVisibleForTargets()));
}
@Override
protected MetaData doUpdateMetaData(final ProxyMetaData entity) {
return smManagement.updateMetaData(
uiDependencies.getEntityFactory().softwareModuleMetadata().update(masterEntityFilter, entity.getKey())
.value(entity.getValue()).targetVisible(entity.isVisibleForTargets()));
}
@Override
protected void doDeleteMetaDataByKey(final String metaDataKey) {
smManagement.deleteMetaData(masterEntityFilter, metaDataKey);
}
private boolean isDuplicate(final String metaDataKey) {
return smManagement.getMetaDataBySoftwareModuleId(masterEntityFilter, metaDataKey).isPresent();
}
@Override
protected MetaDataWindowGrid<Long> getMetaDataWindowGrid() {
return smMetaDataWindowGrid;
}
/**
* @return add widow controller for software module
*/
@Override
public AddMetaDataWindowController getAddMetaDataWindowController() {
return addSmMetaDataWindowController;
}
/**
* @return update widow controller for software module
*/
@Override
public UpdateMetaDataWindowController getUpdateMetaDataWindowController() {
return updateSmMetaDataWindowController;
}
/**
* @return add and update widow layout for software module
*/
@Override
public MetaDataAddUpdateWindowLayout getMetaDataAddUpdateWindowLayout() {
return smMetaDataAddUpdateWindowLayout;
}
@Override
protected void publishEntityModifiedEvent() {
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, masterEntityFilter));
}
}

View File

@@ -1,80 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import com.vaadin.ui.Window;
/**
* Builder for Software module windows
*/
public class SmWindowBuilder extends AbstractEntityWindowBuilder<ProxySoftwareModule> {
private final SoftwareModuleManagement smManagement;
private final SoftwareModuleTypeManagement smTypeManagement;
private final EventView view;
/**
* Constructor for SmWindowBuilder
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smManagement
* SoftwareModuleManagement
* @param smTypeManagement
* SoftwareModuleTypeManagement
* @param view
* EventView
*/
public SmWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement,
final SoftwareModuleTypeManagement smTypeManagement, final EventView view) {
super(uiDependencies);
this.smManagement = smManagement;
this.smTypeManagement = smTypeManagement;
this.view = view;
}
@Override
protected String getWindowId() {
return UIComponentIdProvider.CREATE_POPUP_ID;
}
/**
* @return add window for software module
*/
@Override
public Window getWindowForAdd() {
return getWindowForNewEntity(new AddSmWindowController(uiDependencies, smManagement,
new SmWindowLayout(getI18n(), smTypeManagement), view));
}
/**
* @param proxySm
* ProxySoftwareModule
*
* @return update window for software module
*/
@Override
public Window getWindowForUpdate(final ProxySoftwareModule proxySm) {
return getWindowForEntity(proxySm, new UpdateSmWindowController(uiDependencies, smManagement,
new SmWindowLayout(getI18n(), smTypeManagement)));
}
}

View File

@@ -1,117 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
import org.eclipse.hawkbit.ui.common.data.mappers.TypeToTypeInfoMapper;
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
/**
* Target add/update window layout.
*/
public class SmWindowLayout extends AbstractEntityWindowLayout<ProxySoftwareModule> {
private final SmWindowLayoutComponentBuilder smComponentBuilder;
private final ComboBox<ProxyTypeInfo> smTypeSelect;
private final TextField smName;
private final TextField smVersion;
private final TextField smVendor;
private final TextArea smDescription;
private final CheckBox artifactEncryption;
/**
* Constructor for AbstractTagWindowLayout
*
* @param i18n
* VaadinMessageSource
* @param smTypeManagement
* SoftwareModuleTypeManagement
*/
public SmWindowLayout(final VaadinMessageSource i18n, final SoftwareModuleTypeManagement smTypeManagement) {
super();
final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider = new SoftwareModuleTypeDataProvider<>(
smTypeManagement, new TypeToTypeInfoMapper<>());
this.smComponentBuilder = new SmWindowLayoutComponentBuilder(i18n, smTypeDataProvider);
this.smTypeSelect = smComponentBuilder.createSoftwareModuleTypeCombo(binder);
this.smName = smComponentBuilder.createNameField(binder);
this.smVersion = smComponentBuilder.createVersionField(binder);
this.smVendor = smComponentBuilder.createVendorField(binder);
this.smDescription = smComponentBuilder.createDescription(binder);
this.artifactEncryption = smComponentBuilder.createArtifactEncryptionCheck(binder);
}
/**
* @return software module window layout
*/
@Override
public ComponentContainer getRootComponent() {
final FormLayout smWindowLayout = new FormLayout();
smWindowLayout.setSpacing(true);
smWindowLayout.setMargin(true);
smWindowLayout.setSizeUndefined();
smWindowLayout.addComponent(smTypeSelect);
smWindowLayout.addComponent(smName);
smName.focus();
smWindowLayout.addComponent(smVersion);
smWindowLayout.addComponent(smVendor);
smWindowLayout.addComponent(smDescription);
smWindowLayout.addComponent(artifactEncryption);
return smWindowLayout;
}
/**
* Disable the software module type
*/
public void disableSmTypeSelect() {
smTypeSelect.setEnabled(false);
}
/**
* Disable the software module name
*/
public void disableNameField() {
smName.setEnabled(false);
}
/**
* Disable the software module version
*/
public void disableVersionField() {
smVersion.setEnabled(false);
}
/**
* Disable the software module artifact encryption
*/
public void disableEncryptionField() {
artifactEncryption.setEnabled(false);
}
}

View File

@@ -1,136 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
import org.eclipse.hawkbit.ui.utils.TrimmingStringConverter;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.data.Binder;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
/**
* Builder for software module window layout
*/
public class SmWindowLayoutComponentBuilder {
public static final String TEXTFIELD_VENDOR = "textfield.vendor";
public static final String ARTIFACT_ENCRYPTION = "artifact.encryption";
private final VaadinMessageSource i18n;
private final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider;
/**
* Constructor for SmWindowLayoutComponentBuilder
*
* @param i18n
* VaadinMessageSource
* @param smTypeDataProvider
* SoftwareModuleTypeDataProvider
*/
public SmWindowLayoutComponentBuilder(final VaadinMessageSource i18n,
final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider) {
this.i18n = i18n;
this.smTypeDataProvider = smTypeDataProvider;
}
/**
* Create combo box options for software module types
*
* @param binder
* binder the input will be bound to
*
* @return input component
*/
public ComboBox<ProxyTypeInfo> createSoftwareModuleTypeCombo(final Binder<ProxySoftwareModule> binder) {
return FormComponentBuilder
.createTypeCombo(binder, smTypeDataProvider, i18n, UIComponentIdProvider.SW_MODULE_TYPE, true)
.getComponent();
}
/**
* create name field
*
* @param binder
* binder the input will be bound to
* @return input component
*/
public TextField createNameField(final Binder<ProxySoftwareModule> binder) {
return FormComponentBuilder.createNameInput(binder, i18n, UIComponentIdProvider.SOFT_MODULE_NAME)
.getComponent();
}
/**
* create version field
*
* @param binder
* binder the input will be bound to
* @return input component
*/
public TextField createVersionField(final Binder<ProxySoftwareModule> binder) {
return FormComponentBuilder.createVersionInput(binder, i18n, UIComponentIdProvider.SOFT_MODULE_VERSION)
.getComponent();
}
/**
* Create vendor field
*
* @param binder
* binder the input will be bound to
*
* @return input component
*/
public TextField createVendorField(final Binder<ProxySoftwareModule> binder) {
final TextField smVendor = new TextFieldBuilder(SoftwareModule.VENDOR_MAX_SIZE)
.id(UIComponentIdProvider.SOFT_MODULE_VENDOR).caption(i18n.getMessage(TEXTFIELD_VENDOR))
.prompt(i18n.getMessage(TEXTFIELD_VENDOR)).buildTextComponent();
smVendor.setSizeUndefined();
binder.forField(smVendor).withConverter(new TrimmingStringConverter()).bind(ProxySoftwareModule::getVendor,
ProxySoftwareModule::setVendor);
return smVendor;
}
/**
* create description field
*
* @param binder
* binder the input will be bound to
* @return input component
*/
public TextArea createDescription(final Binder<ProxySoftwareModule> binder) {
return FormComponentBuilder
.createDescriptionInput(binder, i18n, UIComponentIdProvider.ADD_SW_MODULE_DESCRIPTION).getComponent();
}
/**
* Create checkbox for artifact encryption
*
* @param binder
* binder the input will be bound to
*
* @return input component
*/
public CheckBox createArtifactEncryptionCheck(final Binder<ProxySoftwareModule> binder) {
return FormComponentBuilder.createCheckBox(i18n.getMessage(ARTIFACT_ENCRYPTION),
UIComponentIdProvider.ARTIFACT_ENCRYPTION_ID, binder, ProxySoftwareModule::isEncrypted,
ProxySoftwareModule::setEncrypted);
}
}

View File

@@ -1,313 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
import org.eclipse.hawkbit.ui.common.data.filters.SwFilterParams;
import org.eclipse.hawkbit.ui.common.data.mappers.AssignedSoftwareModuleToProxyMapper;
import org.eclipse.hawkbit.ui.common.data.mappers.SoftwareModuleToProxyMapper;
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.event.FilterType;
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
import org.eclipse.hawkbit.ui.common.grid.support.DragAndDropSupport;
import org.eclipse.hawkbit.ui.common.grid.support.FilterSupport;
import org.eclipse.hawkbit.ui.common.grid.support.MasterEntitySupport;
import org.eclipse.hawkbit.ui.common.grid.support.SelectionSupport;
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import com.vaadin.ui.Button;
/**
* Software Module grid.
*/
public class SoftwareModuleGrid extends AbstractGrid<ProxySoftwareModule, SwFilterParams> {
private static final long serialVersionUID = 1L;
private static final String SM_NAME_ID = "smName";
private static final String SM_VERSION_ID = "smVersion";
private static final String SM_DESC_ID = "smDescription";
private static final String SM_VENDOR_ID = "smVendor";
private static final String SM_DELETE_BUTTON_ID = "smDeleteButton";
private final UINotification notification;
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
private final GridLayoutUiState smGridLayoutUiState;
private final transient SoftwareModuleManagement softwareModuleManagement;
private final transient SoftwareModuleToProxyMapper softwareModuleToProxyMapper;
private final transient DeleteSupport<ProxySoftwareModule> swModuleDeleteSupport;
private transient MasterEntitySupport<ProxyDistributionSet> masterEntitySupport;
private final Map<Long, Integer> numberOfArtifactUploadsForSm;
/**
* Constructor for SoftwareModuleGrid
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeFilterLayoutUiState
* TypeFilterLayoutUiState
* @param smGridLayoutUiState
* GridLayoutUiState
* @param softwareModuleManagement
* SoftwareModuleManagement
* @param view
* EventView
*/
public SoftwareModuleGrid(final CommonUiDependencies uiDependencies,
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState,
final SoftwareModuleManagement softwareModuleManagement, final EventView view) {
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
this.smGridLayoutUiState = smGridLayoutUiState;
this.notification = uiDependencies.getUiNotification();
this.softwareModuleManagement = softwareModuleManagement;
this.softwareModuleToProxyMapper = new SoftwareModuleToProxyMapper();
setSelectionSupport(new SelectionSupport<>(this, eventBus, EventLayout.SM_LIST, view, this::mapIdToProxyEntity,
this::getSelectedEntityIdFromUiState, this::setSelectedEntityIdToUiState));
if (smGridLayoutUiState.isMaximized()) {
getSelectionSupport().disableSelection();
} else {
getSelectionSupport().enableMultiSelection();
}
this.swModuleDeleteSupport = new DeleteSupport<>(this, i18n, notification, "caption.software.module",
"caption.softwaremodules", ProxySoftwareModule::getNameAndVersion, this::deleteSoftwareModules,
UIComponentIdProvider.SM_DELETE_CONFIRMATION_DIALOG);
setFilterSupport(new FilterSupport<>(
new SoftwareModuleDataProvider(softwareModuleManagement,
new AssignedSoftwareModuleToProxyMapper(softwareModuleToProxyMapper)),
SwFilterParams::new, this::afterFilterRefresh));
initFilterMappings();
getFilterSupport().setFilter(new SwFilterParams());
this.numberOfArtifactUploadsForSm = new HashMap<>();
}
private void afterFilterRefresh() {
// keep selection on master distribution set change as it does not
// filter out any software module entries, only sorts them
if (masterFilterHasNotChanged()) {
getSelectionSupport().deselectAll();
}
}
private boolean masterFilterHasNotChanged() {
final Long filterDsId = getFilter().map(SwFilterParams::getLastSelectedDistributionId).orElse(null);
final Long masterDsId = getMasterEntitySupport() != null ? getMasterEntitySupport().getMasterId() : null;
return Objects.equals(filterDsId, masterDsId);
}
private void initFilterMappings() {
getFilterSupport().addMapping(FilterType.SEARCH, SwFilterParams::setSearchText,
smGridLayoutUiState.getSearchFilter());
getFilterSupport().addMapping(FilterType.TYPE, SwFilterParams::setSoftwareModuleTypeId,
smTypeFilterLayoutUiState.getClickedTypeId());
}
/**
* Initial method of grid and set style name
*/
@Override
public void init() {
super.init();
addStyleName("grid-row-border");
}
/**
* Map SoftwareModule to Proxy type
*
* @param entityId
* EntityId Long type
*
* @return ProxySoftwareModule
*/
public Optional<ProxySoftwareModule> mapIdToProxyEntity(final long entityId) {
return softwareModuleManagement.get(entityId).map(softwareModuleToProxyMapper::map);
}
private Long getSelectedEntityIdFromUiState() {
return smGridLayoutUiState.getSelectedEntityId();
}
private void setSelectedEntityIdToUiState(final Long entityId) {
smGridLayoutUiState.setSelectedEntityId(entityId);
}
private boolean deleteSoftwareModules(final Collection<ProxySoftwareModule> swModulesToBeDeleted) {
final Collection<Long> swModuleToBeDeletedIds = swModulesToBeDeleted.stream()
.map(ProxyIdentifiableEntity::getId).collect(Collectors.toList());
if (isUploadInProgressForSoftwareModule(swModuleToBeDeletedIds)) {
notification.displayValidationError(i18n.getMessage("message.error.swModule.notDeleted"));
return false;
}
softwareModuleManagement.delete(swModuleToBeDeletedIds);
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
EntityModifiedEventType.ENTITY_REMOVED, ProxySoftwareModule.class, swModuleToBeDeletedIds));
return true;
}
private boolean isUploadInProgressForSoftwareModule(final Collection<Long> swModuleToBeDeletedIds) {
return swModuleToBeDeletedIds.stream().anyMatch(
smId -> numberOfArtifactUploadsForSm.containsKey(smId) && numberOfArtifactUploadsForSm.get(smId) > 0);
}
/**
* Artifacts upload process
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
final FileUploadProgress.FileUploadStatus uploadProgressEventType = fileUploadProgress.getFileUploadStatus();
final Long fileUploadSmId = fileUploadProgress.getFileUploadId().getSoftwareModuleId();
if (fileUploadSmId == null) {
return;
}
if (FileUploadProgress.FileUploadStatus.UPLOAD_STARTED == uploadProgressEventType) {
numberOfArtifactUploadsForSm.merge(fileUploadSmId, 1, Integer::sum);
}
if (FileUploadProgress.FileUploadStatus.UPLOAD_FINISHED == uploadProgressEventType) {
numberOfArtifactUploadsForSm.computeIfPresent(fileUploadSmId, (smId, oldCount) -> {
final Integer newCount = oldCount - 1;
return newCount.equals(0) ? null : newCount;
});
}
}
/**
* Drag and drop for grid elements
*/
public void addDragAndDropSupport() {
setDragAndDropSupportSupport(
new DragAndDropSupport<>(this, i18n, notification, Collections.emptyMap(), eventBus));
if (!smGridLayoutUiState.isMaximized()) {
getDragAndDropSupportSupport().addDragSource();
}
}
/**
* Add master filter type
*/
public void addMasterSupport() {
getFilterSupport().addMapping(FilterType.MASTER, SwFilterParams::setLastSelectedDistributionId);
masterEntitySupport = new MasterEntitySupport<>(getFilterSupport());
initMasterDsStyleGenerator();
}
private void initMasterDsStyleGenerator() {
setStyleGenerator(sm -> {
if (masterEntitySupport.getMasterId() == null || !sm.isAssigned()) {
return null;
}
return String.join("-", UIComponentIdProvider.SM_TYPE_COLOR_CLASS,
String.valueOf(sm.getTypeInfo().getId()));
});
}
/**
* @return gridId of software module grid
*/
@Override
public String getGridId() {
return UIComponentIdProvider.SOFTWARE_MODULE_TABLE;
}
/**
* Add columns to Grid
*/
@Override
public void addColumns() {
addNameColumn().setExpandRatio(2);
addVersionColumn();
addDeleteColumn();
}
private Column<ProxySoftwareModule, String> addNameColumn() {
return GridComponentBuilder.addNameColumn(this, i18n, SM_NAME_ID);
}
private Column<ProxySoftwareModule, String> addVersionColumn() {
return GridComponentBuilder.addVersionColumn(this, i18n, ProxySoftwareModule::getVersion, SM_VERSION_ID);
}
private Column<ProxySoftwareModule, Button> addDeleteColumn() {
return GridComponentBuilder.addDeleteColumn(this, i18n, SM_DELETE_BUTTON_ID, swModuleDeleteSupport,
UIComponentIdProvider.SM_DELET_ICON, e -> permissionChecker.hasDeleteRepositoryPermission());
}
@Override
protected void addMaxColumns() {
addNameColumn().setExpandRatio(7);
addVersionColumn();
addDescriptionColumn().setExpandRatio(5);
addVendorColumn();
GridComponentBuilder.addCreatedAndModifiedColumns(this, i18n);
addDeleteColumn();
getColumns().forEach(column -> column.setHidable(true));
}
private Column<ProxySoftwareModule, String> addDescriptionColumn() {
return GridComponentBuilder.addDescriptionColumn(this, i18n, SM_DESC_ID);
}
private Column<ProxySoftwareModule, String> addVendorColumn() {
return GridComponentBuilder.addColumn(this, ProxySoftwareModule::getVendor).setId(SM_VENDOR_ID)
.setCaption(i18n.getMessage("header.vendor"));
}
/**
* @return ProxyDistributionSet of master entity type
*/
public MasterEntitySupport<ProxyDistributionSet> getMasterEntitySupport() {
return masterEntitySupport;
}
}

View File

@@ -1,102 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.grid.header.AbstractEntityGridHeader;
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
import org.eclipse.hawkbit.ui.common.state.HidableLayoutUiState;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
/**
* Header of Software module table.
*/
public class SoftwareModuleGridHeader extends AbstractEntityGridHeader {
private static final long serialVersionUID = 1L;
private static final String SWM_TABLE_HEADER = "upload.swModuleTable.header";
private static final String SWM_CAPTION = "caption.software.module";
/**
* Constructor for SoftwareModuleGridHeader
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeFilterLayoutUiState
* HidableLayoutUiState
* @param smGridLayoutUiState
* GridLayoutUiState
* @param smWindowBuilder
* SmWindowBuilder
* @param view
* EventView
*/
public SoftwareModuleGridHeader(final CommonUiDependencies uiDependencies,
final HidableLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState,
final SmWindowBuilder smWindowBuilder, final EventView view) {
super(uiDependencies, smTypeFilterLayoutUiState, smGridLayoutUiState, EventLayout.SM_TYPE_FILTER, view);
addAddHeaderSupport(smWindowBuilder);
}
@Override
protected String getCaptionMsg() {
return SWM_TABLE_HEADER;
}
@Override
protected String getSearchFieldId() {
return UIComponentIdProvider.SW_MODULE_SEARCH_TEXT_FIELD;
}
@Override
protected String getSearchResetIconId() {
return UIComponentIdProvider.SW_MODULE_SEARCH_RESET_ICON;
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getEntityType() {
return ProxySoftwareModule.class;
}
@Override
protected String getFilterButtonsIconId() {
return UIComponentIdProvider.SHOW_SM_TYPE_ICON;
}
@Override
protected String getMaxMinIconId() {
return UIComponentIdProvider.SW_MAX_MIN_TABLE_ICON;
}
@Override
protected EventLayout getLayout() {
return EventLayout.SM_LIST;
}
@Override
protected boolean hasCreatePermission() {
return permChecker.hasCreateRepositoryPermission();
}
@Override
protected String getAddIconId() {
return UIComponentIdProvider.SW_MODULE_ADD_BUTTON;
}
@Override
protected String getAddWindowCaptionMsg() {
return SWM_CAPTION;
}
}

View File

@@ -1,129 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetails;
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsHeader;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener;
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport;
import org.eclipse.hawkbit.ui.common.layout.listener.FilterChangedListener;
import org.eclipse.hawkbit.ui.common.layout.listener.GenericEventListener;
import org.eclipse.hawkbit.ui.common.layout.listener.SelectGridEntityListener;
import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener;
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelectionAwareSupport;
import org.eclipse.hawkbit.ui.common.softwaremodule.AbstractSoftwareModuleGridLayout;
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
/**
* Software module table layout. (Upload Management)
*/
public class SoftwareModuleGridLayout extends AbstractSoftwareModuleGridLayout {
private static final long serialVersionUID = 1L;
private final SoftwareModuleGridHeader softwareModuleGridHeader;
private final SoftwareModuleGrid softwareModuleGrid;
private final SoftwareModuleDetailsHeader softwareModuleDetailsHeader;
private final SoftwareModuleDetails softwareModuleDetails;
/**
* Constructor for SoftwareModuleGridLayout
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param softwareModuleManagement
* SoftwareModuleManagement
* @param softwareModuleTypeManagement
* SoftwareModuleTypeManagement
* @param smTypeFilterLayoutUiState
* TypeFilterLayoutUiState
* @param smGridLayoutUiState
* GridLayoutUiState
*/
public SoftwareModuleGridLayout(final CommonUiDependencies uiDependencies,
final SoftwareModuleManagement softwareModuleManagement,
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState) {
super(uiDependencies, softwareModuleManagement, softwareModuleTypeManagement, EventView.UPLOAD);
this.softwareModuleGridHeader = new SoftwareModuleGridHeader(uiDependencies, smTypeFilterLayoutUiState,
smGridLayoutUiState, getSmWindowBuilder(), getEventView());
this.softwareModuleGridHeader.buildHeader();
this.softwareModuleGrid = new SoftwareModuleGrid(uiDependencies, smTypeFilterLayoutUiState, smGridLayoutUiState,
softwareModuleManagement, getEventView());
this.softwareModuleGrid.init();
this.softwareModuleDetailsHeader = new SoftwareModuleDetailsHeader(uiDependencies, getSmWindowBuilder(),
getSmMetaDataWindowBuilder());
this.softwareModuleDetailsHeader.buildHeader();
this.softwareModuleDetails = new SoftwareModuleDetails(uiDependencies, softwareModuleManagement,
softwareModuleTypeManagement, getSmMetaDataWindowBuilder());
this.softwareModuleDetails.buildDetails();
final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_LIST, getEventView());
addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxySoftwareModule.class,
layoutViewAware, softwareModuleGrid.getFilterSupport()));
addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware,
getMasterSmAwareComponents()));
addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), layoutViewAware,
softwareModuleGrid.getSelectionSupport()));
addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxySoftwareModule.class)
.viewAware(layoutViewAware).entityModifiedAwareSupports(getSmModifiedAwareSupports()).build());
addEventListener(new GenericEventListener<>(uiDependencies.getEventBus(), EventTopics.FILE_UPLOAD_CHANGED,
this::onUploadChanged));
buildLayout(softwareModuleGridHeader, softwareModuleGrid, softwareModuleDetailsHeader, softwareModuleDetails);
}
private List<MasterEntityAwareComponent<ProxySoftwareModule>> getMasterSmAwareComponents() {
return Arrays.asList(softwareModuleDetailsHeader, softwareModuleDetails);
}
private List<EntityModifiedAwareSupport> getSmModifiedAwareSupports() {
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(softwareModuleGrid::refreshAll),
EntityModifiedSelectionAwareSupport.of(softwareModuleGrid.getSelectionSupport(),
softwareModuleGrid::mapIdToProxyEntity));
}
/**
* Verifies when file upload is in progress
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
softwareModuleGrid.onUploadChanged(fileUploadProgress);
}
@Override
protected SoftwareModuleGridHeader getSoftwareModuleGridHeader() {
return softwareModuleGridHeader;
}
@Override
protected SoftwareModuleGrid getSoftwareModuleGrid() {
return softwareModuleGrid;
}
}

View File

@@ -1,119 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtable;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.common.AbstractUpdateNamedEntityWindowController;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* Controller for update software module window
*/
public class UpdateSmWindowController
extends AbstractUpdateNamedEntityWindowController<ProxySoftwareModule, ProxySoftwareModule, SoftwareModule> {
private final SoftwareModuleManagement smManagement;
private final SmWindowLayout layout;
private final ProxySmValidator validator;
private String nameBeforeEdit;
private String versionBeforeEdit;
/**
* Constructor for UpdateSmWindowController
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smManagement
* SoftwareModuleManagement
* @param layout
* SmWindowLayout
*/
public UpdateSmWindowController(final CommonUiDependencies uiDependencies,
final SoftwareModuleManagement smManagement, final SmWindowLayout layout) {
super(uiDependencies);
this.smManagement = smManagement;
this.layout = layout;
this.validator = new ProxySmValidator(uiDependencies);
}
@Override
protected ProxySoftwareModule buildEntityFromProxy(final ProxySoftwareModule proxyEntity) {
final ProxySoftwareModule sm = new ProxySoftwareModule();
sm.setId(proxyEntity.getId());
sm.setTypeInfo(proxyEntity.getTypeInfo());
sm.setName(proxyEntity.getName());
sm.setVersion(proxyEntity.getVersion());
sm.setVendor(proxyEntity.getVendor());
sm.setDescription(proxyEntity.getDescription());
sm.setEncrypted(proxyEntity.isEncrypted());
nameBeforeEdit = proxyEntity.getName();
versionBeforeEdit = proxyEntity.getVersion();
return sm;
}
@Override
public EntityWindowLayout<ProxySoftwareModule> getLayout() {
return layout;
}
@Override
protected void adaptLayout(final ProxySoftwareModule proxyEntity) {
layout.disableSmTypeSelect();
layout.disableNameField();
layout.disableVersionField();
layout.disableEncryptionField();
}
@Override
protected SoftwareModule persistEntityInRepository(final ProxySoftwareModule entity) {
final SoftwareModuleUpdate smUpdate = getEntityFactory().softwareModule().update(entity.getId())
.vendor(entity.getVendor()).description(entity.getDescription());
return smManagement.update(smUpdate);
}
@Override
protected String getDisplayableName(final SoftwareModule entity) {
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
}
@Override
protected String getDisplayableNameForFailedMessage(final ProxySoftwareModule entity) {
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
return ProxySoftwareModule.class;
}
@Override
protected boolean isEntityValid(final ProxySoftwareModule entity) {
final String name = entity.getName();
final String version = entity.getVersion();
final Long typeId = entity.getTypeInfo().getId();
return validator.isEntityValid(entity, () -> hasNameOrVersionChanged(name, version)
&& smManagement.getByNameAndVersionAndType(name, version, typeId).isPresent());
}
private boolean hasNameOrVersionChanged(final String trimmedName, final String trimmedVersion) {
return !nameBeforeEdit.equals(trimmedName) || !versionBeforeEdit.equals(trimmedVersion);
}
}

View File

@@ -1,88 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.ui.common.AbstractAddNamedEntityWindowController;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
import org.eclipse.hawkbit.ui.common.type.ProxyTypeValidator;
/**
* Controller for Add software module type window
*/
public class AddSmTypeWindowController
extends AbstractAddNamedEntityWindowController<ProxyType, ProxyType, SoftwareModuleType> {
private final SoftwareModuleTypeManagement smTypeManagement;
private final SmTypeWindowLayout layout;
private final ProxyTypeValidator validator;
/**
* Constructor for AddSmTypeWindowController
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeManagement
* SoftwareModuleTypeManagement
* @param layout
* SmTypeWindowLayout
*/
public AddSmTypeWindowController(final CommonUiDependencies uiDependencies,
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
super(uiDependencies);
this.smTypeManagement = smTypeManagement;
this.layout = layout;
this.validator = new ProxyTypeValidator(uiDependencies);
}
@Override
public EntityWindowLayout<ProxyType> getLayout() {
return layout;
}
@Override
protected ProxyType buildEntityFromProxy(final ProxyType proxyEntity) {
// We ignore the method parameter, because we are interested in the
// empty object, that we can populate with defaults
return new ProxyType();
}
@Override
protected SoftwareModuleType persistEntityInRepository(final ProxyType entity) {
final int assignNumber = entity.getSmTypeAssign() == SmTypeAssign.SINGLE ? 1 : Integer.MAX_VALUE;
return smTypeManagement
.create(getEntityFactory().softwareModuleType().create().key(entity.getKey()).name(entity.getName())
.description(entity.getDescription()).colour(entity.getColour()).maxAssignments(assignNumber));
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
return ProxyType.class;
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
return ProxySoftwareModule.class;
}
@Override
protected boolean isEntityValid(final ProxyType entity) {
return validator.isSmTypeValid(entity, () -> smTypeManagement.getByKey(entity.getKey()).isPresent(),
() -> smTypeManagement.getByName(entity.getName()).isPresent());
}
}

View File

@@ -1,70 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import com.vaadin.ui.Window;
/**
* Builder for software module type window
*/
public class SmTypeWindowBuilder extends AbstractEntityWindowBuilder<ProxyType> {
private final SoftwareModuleTypeManagement smTypeManagement;
/**
* Constructor for SmTypeWindowBuilder
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeManagement
* SoftwareModuleTypeManagement
*/
public SmTypeWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleTypeManagement smTypeManagement) {
super(uiDependencies);
this.smTypeManagement = smTypeManagement;
}
@Override
protected String getWindowId() {
return UIComponentIdProvider.TAG_POPUP_ID;
}
/**
* Add window for software module type
*
* @return Window of Software module type
*/
@Override
public Window getWindowForAdd() {
return getWindowForNewEntity(
new AddSmTypeWindowController(uiDependencies, smTypeManagement, new SmTypeWindowLayout(uiDependencies)));
}
/**
* Update window for software module type
*
* @param proxyType
* ProxyType
*
* @return Window of Software module type
*/
@Override
public Window getWindowForUpdate(final ProxyType proxyType) {
return getWindowForEntity(proxyType,
new UpdateSmTypeWindowController(uiDependencies, smTypeManagement, new SmTypeWindowLayout(uiDependencies)));
}
}

View File

@@ -1,71 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
import org.eclipse.hawkbit.ui.management.tag.TagWindowLayout;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.RadioButtonGroup;
import com.vaadin.ui.TextField;
/**
* Software module type Window Layout view
*/
public class SmTypeWindowLayout extends TagWindowLayout<ProxyType> {
private final SmTypeWindowLayoutComponentBuilder smTypeComponentBuilder;
private final TextField typeKey;
private final RadioButtonGroup<SmTypeAssign> smTypeAssignOptionGroup;
/**
* Constructor for SmTypeWindowLayout
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
public SmTypeWindowLayout(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
this.smTypeComponentBuilder = new SmTypeWindowLayoutComponentBuilder(i18n);
this.typeKey = FormComponentBuilder.createTypeKeyField(binder, i18n);
this.smTypeAssignOptionGroup = smTypeComponentBuilder.createSmTypeAssignOptionGroup(binder);
this.colorPickerComponent.getColorPickerBtn().setCaption(i18n.getMessage("label.choose.type.color"));
}
@Override
protected FormLayout buildFormLayout() {
final FormLayout formLayout = super.buildFormLayout();
formLayout.addComponent(typeKey, formLayout.getComponentCount() - 1);
formLayout.addComponent(smTypeAssignOptionGroup, formLayout.getComponentCount() - 1);
return formLayout;
}
/**
* Disable the software module type key text field
*/
public void disableTypeKey() {
typeKey.setEnabled(false);
}
/**
* Disable the software module type assign option
*/
public void disableTypeAssignOptionGroup() {
smTypeAssignOptionGroup.setEnabled(false);
}
}

View File

@@ -1,77 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.data.Binder;
import com.vaadin.ui.RadioButtonGroup;
/**
* Builder for software module type window layout component
*/
public class SmTypeWindowLayoutComponentBuilder {
public static final String TEXTFIELD_KEY = "textfield.key";
private final VaadinMessageSource i18n;
/**
* Constructor for SmTypeWindowLayoutComponentBuilder
*
* @param i18n
* VaadinMessageSource
*/
public SmTypeWindowLayoutComponentBuilder(final VaadinMessageSource i18n) {
this.i18n = i18n;
}
/**
* Create software module type assignment group
*
* @param binder
* Vaadin binder of ProxyType
*
* @return RadioButtonGroup of software module type assignment
*/
public RadioButtonGroup<SmTypeAssign> createSmTypeAssignOptionGroup(final Binder<ProxyType> binder) {
final RadioButtonGroup<SmTypeAssign> smTypeAssignOptionGroup = new RadioButtonGroup<>();
smTypeAssignOptionGroup.setId(UIComponentIdProvider.ASSIGN_OPTION_GROUP_SOFTWARE_MODULE_TYPE_ID);
smTypeAssignOptionGroup.setItemCaptionGenerator(item -> {
switch (item) {
case SINGLE:
return i18n.getMessage("label.singleAssign.type");
case MULTI:
return i18n.getMessage("label.multiAssign.type");
default:
return null;
}
});
smTypeAssignOptionGroup.setItemDescriptionGenerator(item -> {
switch (item) {
case SINGLE:
return i18n.getMessage("label.singleAssign.type.desc");
case MULTI:
return i18n.getMessage("label.multiAssign.type.desc");
default:
return null;
}
});
binder.forField(smTypeAssignOptionGroup).bind(ProxyType::getSmTypeAssign, ProxyType::setSmTypeAssign);
smTypeAssignOptionGroup.setItems(SmTypeAssign.values());
return smTypeAssignOptionGroup;
}
}

View File

@@ -1,124 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.ui.common.AbstractUpdateNamedEntityWindowController;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
import org.eclipse.hawkbit.ui.common.type.ProxyTypeValidator;
/**
* Controller for update software module type window
*/
public class UpdateSmTypeWindowController
extends AbstractUpdateNamedEntityWindowController<ProxyType, ProxyType, SoftwareModuleType> {
private final SoftwareModuleTypeManagement smTypeManagement;
private final SmTypeWindowLayout layout;
private final ProxyTypeValidator validator;
private String nameBeforeEdit;
private String keyBeforeEdit;
/**
* Constructor for UpdateSmTypeWindowController
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeManagement
* SoftwareModuleTypeManagement
* @param layout
* SmTypeWindowLayout
*/
public UpdateSmTypeWindowController(final CommonUiDependencies uiDependencies,
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
super(uiDependencies);
this.smTypeManagement = smTypeManagement;
this.layout = layout;
this.validator = new ProxyTypeValidator(uiDependencies);
}
@Override
protected ProxyType buildEntityFromProxy(final ProxyType proxyEntity) {
final ProxyType smType = new ProxyType();
smType.setId(proxyEntity.getId());
smType.setName(proxyEntity.getName());
smType.setDescription(proxyEntity.getDescription());
smType.setColour(proxyEntity.getColour());
smType.setKey(proxyEntity.getKey());
smType.setSmTypeAssign(getSmTypeAssignById(proxyEntity.getId()));
nameBeforeEdit = proxyEntity.getName();
keyBeforeEdit = proxyEntity.getKey();
return smType;
}
private SmTypeAssign getSmTypeAssignById(final Long id) {
return smTypeManagement.get(id)
.map(smType -> smType.getMaxAssignments() == 1 ? SmTypeAssign.SINGLE : SmTypeAssign.MULTI)
.orElse(SmTypeAssign.SINGLE);
}
@Override
public EntityWindowLayout<ProxyType> getLayout() {
return layout;
}
@Override
protected void adaptLayout(final ProxyType proxyEntity) {
layout.disableTagName();
layout.disableTypeKey();
layout.disableTypeAssignOptionGroup();
}
@Override
protected SoftwareModuleType persistEntityInRepository(final ProxyType entity) {
final SoftwareModuleTypeUpdate smTypeUpdate = getEntityFactory().softwareModuleType().update(entity.getId())
.description(entity.getDescription()).colour(entity.getColour());
return smTypeManagement.update(smTypeUpdate);
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
return ProxyType.class;
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
return ProxySoftwareModule.class;
}
@Override
protected boolean isEntityValid(final ProxyType entity) {
final String name = entity.getName();
final String key = entity.getKey();
return validator.isSmTypeValid(entity,
() -> hasKeyChanged(key) && smTypeManagement.getByKey(key).isPresent(),
() -> hasNameChanged(name) && smTypeManagement.getByName(name).isPresent());
}
private boolean hasNameChanged(final String trimmedName) {
return !nameBeforeEdit.equals(trimmedName);
}
private boolean hasKeyChanged(final String trimmedKey) {
return !keyBeforeEdit.equals(trimmedKey);
}
}

View File

@@ -1,123 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.mappers.TypeToProxyTypeMapper;
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractTypeFilterButtons;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import com.vaadin.ui.Window;
/**
* Software module type filter buttons.
*
*/
public class SMTypeFilterButtons extends AbstractTypeFilterButtons {
private static final long serialVersionUID = 1L;
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
private final EventView view;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param softwareModuleTypeManagement
* SoftwareModuleTypeManagement
* @param smTypeWindowBuilder
* SmTypeWindowBuilder
* @param typeFilterLayoutUiState
* TypeFilterLayoutUiState
* @param view
* EventView
*/
public SMTypeFilterButtons(final CommonUiDependencies uiDependencies,
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
final SmTypeWindowBuilder smTypeWindowBuilder, final TypeFilterLayoutUiState typeFilterLayoutUiState,
final EventView view) {
super(uiDependencies, typeFilterLayoutUiState);
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
this.smTypeWindowBuilder = smTypeWindowBuilder;
this.view = view;
init();
setDataProvider(
new SoftwareModuleTypeDataProvider<>(softwareModuleTypeManagement, new TypeToProxyTypeMapper<>()));
}
/**
* Gets id of the software module type grid.
*
* @return id of the grid
*/
@Override
public String getGridId() {
return UIComponentIdProvider.SW_MODULE_TYPE_TABLE_ID;
}
@Override
protected String getMessageKeyEntityTypeSing() {
return "caption.entity.software.module.type";
}
@Override
protected String getMessageKeyEntityTypePlur() {
return "caption.entity.software.module.types";
}
@Override
protected String getFilterButtonIdPrefix() {
return UIComponentIdProvider.SOFTWARE_MODULE_TYPE_ID_PREFIXS;
}
@Override
protected boolean isDefaultType(final ProxyType type) {
// We do not have default type for software module
return false;
}
@Override
protected Class<? extends ProxyIdentifiableEntity> getFilterMasterEntityType() {
return ProxySoftwareModule.class;
}
@Override
protected EventView getView() {
return view;
}
@Override
protected void deleteType(final ProxyType typeToDelete) {
softwareModuleTypeManagement.delete(typeToDelete.getId());
}
@Override
protected Window getUpdateWindow(final ProxyType clickedFilter) {
return smTypeWindowBuilder.getWindowForUpdate(clickedFilter);
}
@Override
protected boolean typeExists(final Long typeId) {
return softwareModuleTypeManagement.exists(typeId);
}
}

View File

@@ -1,97 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.grid.header.AbstractFilterHeader;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import com.vaadin.ui.Window;
/**
* Software module type filter buttons header.
*/
public class SMTypeFilterHeader extends AbstractFilterHeader {
private static final long serialVersionUID = 1L;
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
private final EventView view;
/**
* Constructor for SMTypeFilterHeader
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param smTypeWindowBuilder
* SmTypeWindowBuilder
* @param smTypeFilterLayoutUiState
* TypeFilterLayoutUiState
* @param view
* EventView
*/
public SMTypeFilterHeader(final CommonUiDependencies uiDependencies, final SmTypeWindowBuilder smTypeWindowBuilder,
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final EventView view) {
super(uiDependencies.getI18n(), uiDependencies.getPermChecker(), uiDependencies.getEventBus());
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
this.smTypeWindowBuilder = smTypeWindowBuilder;
this.view = view;
buildHeader();
}
@Override
protected String getHeaderCaptionMsgKey() {
return UIMessageIdProvider.CAPTION_FILTER_BY_TYPE;
}
@Override
protected String getCrudMenuBarId() {
return UIComponentIdProvider.SOFT_MODULE_TYPE_MENU_BAR_ID;
}
@Override
protected Window getWindowForAdd() {
return smTypeWindowBuilder.getWindowForAdd();
}
@Override
protected String getAddEntityWindowCaptionMsgKey() {
return "caption.type";
}
@Override
protected String getCloseIconId() {
return UIComponentIdProvider.HIDE_SM_TYPES;
}
@Override
protected void updateHiddenUiState() {
smTypeFilterLayoutUiState.setHidden(true);
}
@Override
protected EventLayout getLayout() {
return EventLayout.SM_TYPE_FILTER;
}
@Override
protected EventView getView() {
return view;
}
}

View File

@@ -1,120 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
import java.util.Arrays;
import java.util.List;
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.event.EventLayout;
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
import org.eclipse.hawkbit.ui.common.event.EventView;
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterLayout;
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener;
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport;
import org.eclipse.hawkbit.ui.common.layout.listener.GridActionsVisibilityListener;
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGenericSupport;
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
import com.vaadin.ui.ComponentContainer;
/**
* Software module type filter buttons layout.
*/
public class SMTypeFilterLayout extends AbstractFilterLayout {
private static final long serialVersionUID = 1L;
private final SMTypeFilterHeader smTypeFilterHeader;
private final SMTypeFilterButtons smTypeFilterButtons;
private final transient GridActionsVisibilityListener gridActionsVisibilityListener;
private final transient EntityModifiedListener<ProxyType> entityModifiedListener;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
* @param softwareModuleTypeManagement
* SoftwareModuleTypeManagement
* @param smTypeFilterLayoutUiState
* SMTypeFilterLayoutUiState
* @param eventView
* {@link EventView}
*/
public SMTypeFilterLayout(final CommonUiDependencies uiDependencies,
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final EventView eventView) {
final SmTypeWindowBuilder smTypeWindowBuilder = new SmTypeWindowBuilder(uiDependencies,
softwareModuleTypeManagement);
this.smTypeFilterHeader = new SMTypeFilterHeader(uiDependencies, smTypeWindowBuilder, smTypeFilterLayoutUiState,
eventView);
this.smTypeFilterButtons = new SMTypeFilterButtons(uiDependencies, softwareModuleTypeManagement,
smTypeWindowBuilder, smTypeFilterLayoutUiState, eventView);
final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_TYPE_FILTER, eventView);
this.gridActionsVisibilityListener = new GridActionsVisibilityListener(uiDependencies.getEventBus(),
layoutViewAware, smTypeFilterButtons::hideActionColumns, smTypeFilterButtons::showEditColumn,
smTypeFilterButtons::showDeleteColumn);
this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(),
ProxyType.class).parentEntityType(ProxySoftwareModule.class).viewAware(layoutViewAware)
.entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build();
buildLayout();
}
private List<EntityModifiedAwareSupport> getEntityModifiedAwareSupports() {
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(this::refreshFilterButtons),
EntityModifiedGenericSupport.of(null, null, smTypeFilterButtons::resetFilterOnTypesDeleted));
}
protected void refreshFilterButtons() {
smTypeFilterButtons.refreshAll();
}
@Override
protected SMTypeFilterHeader getFilterHeader() {
return smTypeFilterHeader;
}
@Override
protected ComponentContainer getFilterContent() {
return wrapFilterContent(smTypeFilterButtons);
}
@Override
public void restoreState() {
smTypeFilterButtons.restoreState();
}
@Override
public void onViewEnter() {
smTypeFilterButtons.reevaluateFilter();
}
@Override
public void subscribeListeners() {
gridActionsVisibilityListener.subscribe();
entityModifiedListener.subscribe();
}
@Override
public void unsubscribeListeners() {
gridActionsVisibilityListener.unsubscribe();
entityModifiedListener.unsubscribe();
}
}

View File

@@ -1,352 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
import org.eclipse.hawkbit.repository.exception.ArtifactEncryptionFailedException;
import org.eclipse.hawkbit.repository.exception.ArtifactEncryptionUnsupportedException;
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.ui.UI;
/**
* Abstract base class for transferring files from the browser to the
* repository.
*/
public abstract class AbstractFileTransferHandler implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(AbstractFileTransferHandler.class);
private static final String MESSAGE_UPLOAD_FAILED = "message.upload.failed";
private volatile boolean uploadInterrupted;
private volatile String failureReason;
private final ArtifactUploadState artifactUploadState;
private final transient UIEventBus eventBus;
private final transient ArtifactManagement artifactManagement;
private final VaadinMessageSource i18n;
private final transient Lock uploadLock;
protected static final RegexCharacterCollection ILLEGAL_FILENAME_CHARACTERS = new RegexCharacterCollection(
RegexChar.GREATER_THAN, RegexChar.LESS_THAN, RegexChar.SLASHES);
AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n,
final Lock uploadLock) {
this.artifactManagement = artifactManagement;
this.i18n = i18n;
this.eventBus = SpringContextHolder.getInstance().getBean(EventBus.UIEventBus.class);
this.artifactUploadState = SpringContextHolder.getInstance().getBean(ArtifactUploadState.class);
this.uploadLock = uploadLock;
}
protected boolean isUploadInterrupted() {
return uploadInterrupted;
}
protected void resetState() {
uploadInterrupted = false;
failureReason = null;
}
protected ArtifactUploadState getUploadState() {
return artifactUploadState;
}
protected VaadinMessageSource getI18n() {
return i18n;
}
protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId,
final String mimeType) {
SpringContextHolder.getInstance().getBean("uiExecutor", Executor.class)
.execute(new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent(),
uploadLock));
}
private void interruptUploadAndSetReason(final String failureReason) {
uploadInterrupted = true;
this.failureReason = failureReason;
}
protected void interruptUploadDueToUploadFailed() {
interruptUploadAndSetReason(i18n.getMessage(MESSAGE_UPLOAD_FAILED));
}
protected void interruptUploadDueToAssignmentQuotaExceeded() {
interruptUploadAndSetReason(i18n.getMessage("message.upload.assignmentQuota"));
}
protected void interruptUploadDueToFileSizeQuotaExceeded(final String exceededValue) {
interruptUploadAndSetReason(i18n.getMessage("message.upload.fileSizeQuota", exceededValue));
}
protected void interruptUploadDueToStorageQuotaExceeded(final String exceededValue) {
interruptUploadAndSetReason(i18n.getMessage("message.upload.storageQuota", exceededValue));
}
protected void interruptUploadDueToDuplicateFile() {
interruptUploadAndSetReason(i18n.getMessage("message.no.duplicateFiles"));
}
protected void interruptUploadDueToIllegalFilename() {
interruptUploadAndSetReason(i18n.getMessage("message.uploadedfile.illegalFilename"));
}
protected void interruptUploadDueToEncryptionError() {
interruptUploadAndSetReason(i18n.getMessage("message.encryption.failed"));
}
protected boolean isFileAlreadyContainedInSoftwareModule(final FileUploadId newFileUploadId,
final SoftwareModule softwareModule) {
for (final Artifact artifact : softwareModule.getArtifacts()) {
final FileUploadId existingId = new FileUploadId(artifact.getFilename(), softwareModule);
if (existingId.equals(newFileUploadId)) {
return true;
}
}
return false;
}
protected void publishUploadStarted(final FileUploadId fileUploadId) {
LOG.info("Upload started for file {}", fileUploadId);
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
FileUploadStatus.UPLOAD_STARTED);
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
}
protected void publishUploadProgressEvent(final FileUploadId fileUploadId, final long bytesReceived,
final long fileSize) {
if (LOG.isTraceEnabled()) {
LOG.trace("Upload in progress for file {} - {}%", fileUploadId,
String.format("%.0f", (double) bytesReceived / (double) fileSize * 100));
}
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
FileUploadStatus.UPLOAD_IN_PROGRESS, bytesReceived, fileSize);
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
}
protected void publishUploadFinishedEvent(final FileUploadId fileUploadId) {
LOG.debug("Upload finished for file {}", fileUploadId);
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
FileUploadStatus.UPLOAD_FINISHED);
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, 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(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
}
protected void publishUploadFailedEvent(final FileUploadId fileUploadId) {
LOG.info("Upload failed for file {} due to reason: {}", fileUploadId, failureReason);
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
FileUploadStatus.UPLOAD_FAILED,
StringUtils.hasText(failureReason) ? failureReason : i18n.getMessage(MESSAGE_UPLOAD_FAILED));
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
}
protected void publishArtifactsChanged(final FileUploadId fileUploadId) {
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, fileUploadId.getSoftwareModuleId()));
}
protected void publishUploadFailedAndFinishedEvent(final FileUploadId fileUploadId) {
publishUploadFailedEvent(fileUploadId);
publishUploadFinishedEvent(fileUploadId);
}
protected void assertStateConsistency(final FileUploadId fileUploadId, final String filenameExtractedFromEvent) {
if (!filenameExtractedFromEvent.equals(fileUploadId.getFilename())) {
throw new IllegalStateException("Event filename " + filenameExtractedFromEvent + " but stored filename "
+ fileUploadId.getFilename());
}
}
protected static void tryToCloseIOStream(final OutputStream outputStream) {
if (outputStream != null) {
try {
outputStream.close();
} catch (final IOException e1) {
LOG.warn("Closing output stream caused by", e1);
}
}
}
protected static void tryToCloseIOStream(final InputStream inputStream) {
if (inputStream != null) {
try {
inputStream.close();
} catch (final IOException e1) {
LOG.warn("Closing input stream caused by", e1);
}
}
}
private final class TransferArtifactToRepositoryRunnable implements Runnable {
private final InputStream inputStream;
private final FileUploadId fileUploadId;
private final String mimeType;
private final UI vaadinUi;
private final Lock uploadLock;
/**
* Constructor for TransferArtifactToRepositoryRunnable
*
* @param inputStream
* InputStream
* @param fileUploadId
* FileUploadId
* @param mimeType
* String
* @param vaadinUi
* UI
* @param uploadLock
* Lock
*/
public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId,
final String mimeType, final UI vaadinUi, final Lock uploadLock) {
this.inputStream = inputStream;
this.fileUploadId = fileUploadId;
this.mimeType = mimeType;
this.vaadinUi = vaadinUi;
this.uploadLock = uploadLock;
}
/**
* a lock object is used here that is propagated down from
* {@link org.eclipse.hawkbit.ui.artifacts.UploadArtifactView}. It
* ensures that from within the same UI instance all uploads are
* executed sequentially to avoid issues that occur when multiple files
* are processed at the same time (e.g. regarding quota checks)
*/
@Override
public void run() {
try {
UI.setCurrent(vaadinUi);
uploadLock.lock();
streamToRepository();
} catch (final FileSizeQuotaExceededException e) {
interruptUploadDueToFileSizeQuotaExceeded(e.getExceededQuotaValueString());
publishUploadFailedAndFinishedEvent(fileUploadId);
LOG.debug("Upload failed due to file size quota exceeded:", e);
} catch (final StorageQuotaExceededException e) {
interruptUploadDueToStorageQuotaExceeded(e.getExceededQuotaValueString());
publishUploadFailedAndFinishedEvent(fileUploadId);
LOG.debug("Upload failed due to storage quota exceeded:", e);
} catch (final AssignmentQuotaExceededException e) {
interruptUploadDueToAssignmentQuotaExceeded();
publishUploadFailedAndFinishedEvent(fileUploadId);
LOG.debug("Upload failed due to assignment quota exceeded:", e);
} catch (final ArtifactEncryptionUnsupportedException | ArtifactEncryptionFailedException e) {
interruptUploadDueToEncryptionError();
publishUploadFailedAndFinishedEvent(fileUploadId);
LOG.warn("Upload failed due to encryption error", e);
} catch (final RuntimeException e) {
interruptUploadDueToUploadFailed();
publishUploadFailedAndFinishedEvent(fileUploadId);
LOG.warn("Failed to transfer file to repository", e);
} finally {
tryToCloseIOStream(inputStream);
uploadLock.unlock();
}
}
private void streamToRepository() {
if (fileUploadId == null) {
throw new ArtifactUploadFailedException();
}
final String filename = fileUploadId.getFilename();
final Artifact artifact = uploadArtifact(filename);
if (isUploadInterrupted()) {
LOG.warn("Upload of {} was interrupted", filename);
handleUploadFailure(artifact);
publishUploadFinishedEvent(fileUploadId);
return;
}
publishUploadSucceeded(fileUploadId, artifact.getSize());
publishUploadFinishedEvent(fileUploadId);
publishArtifactsChanged(fileUploadId);
}
private Artifact uploadArtifact(final String filename) {
LOG.debug("Transfering file {} directly to repository", filename);
try {
return artifactManagement.create(new ArtifactUpload(inputStream, fileUploadId.getSoftwareModuleId(),
filename, null, null, null, true, mimeType, -1));
} catch (final InvalidSHA1HashException | InvalidMD5HashException e) {
throw new ArtifactUploadFailedException(e);
}
}
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);
}
}
}

View File

@@ -1,183 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
import org.eclipse.hawkbit.repository.SizeConversionHelper;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.ByteStreams;
import com.vaadin.server.StreamVariable;
/**
* {@link StreamVariable} implementation to read and upload a file. One instance
* per file stream is used.
*
* The handler manages the output to the user and at the same time ensures that
* the upload does not exceed the configured max file size.
*
*/
public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandler implements StreamVariable {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(FileTransferHandlerStreamVariable.class);
private final long maxSize;
private final long fileSize;
private final String mimeType;
private final FileUploadId fileUploadId;
private final SoftwareModule selectedSoftwareModule;
FileTransferHandlerStreamVariable(final String fileName, final long fileSize, final long maxSize,
final String mimeType, final SoftwareModule selectedSw, final ArtifactManagement artifactManagement,
final VaadinMessageSource i18n, final Lock uploadLock) {
super(artifactManagement, i18n, uploadLock);
this.fileSize = fileSize;
this.maxSize = maxSize;
this.mimeType = mimeType;
this.selectedSoftwareModule = selectedSw;
this.fileUploadId = new FileUploadId(fileName, selectedSw);
publishUploadStarted(fileUploadId);
}
/**
* Checks for duplication and invalid file name during file upload process
*
* @param event
* StreamingStartEvent
*/
@Override
public void streamingStarted(final StreamingStartEvent event) {
assertStateConsistency(fileUploadId, event.getFileName());
if (RegexCharacterCollection.stringContainsCharacter(event.getFileName(), ILLEGAL_FILENAME_CHARACTERS)) {
LOG.debug("Filename contains illegal characters {} for upload {}", fileUploadId.getFilename(),
fileUploadId);
interruptUploadDueToIllegalFilename();
} else if (isFileAlreadyContainedInSoftwareModule(fileUploadId, selectedSoftwareModule)) {
LOG.debug("File {} already contained in Software Module {}", fileUploadId.getFilename(),
selectedSoftwareModule);
interruptUploadDueToDuplicateFile();
}
}
/**
* get the output stream of uploaded file
*
* @return OutputStream
*/
@Override
public final OutputStream getOutputStream() {
if (isUploadInterrupted()) {
return ByteStreams.nullOutputStream();
}
// we return the output stream - we cannot close it here
@SuppressWarnings("squid:S2095")
final PipedOutputStream outputStream = new PipedOutputStream();
final PipedInputStream inputStream;
try {
inputStream = new PipedInputStream(outputStream);
publishUploadProgressEvent(fileUploadId, 0, fileSize);
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
} catch (final IOException e) {
LOG.warn("Creating piped Stream failed {}.", e.getMessage());
tryToCloseIOStream(outputStream);
// input stream is not created in case of and IOException here
interruptUploadDueToUploadFailed();
publishUploadFailedAndFinishedEvent(fileUploadId);
return ByteStreams.nullOutputStream();
}
return outputStream;
}
/**
* listen progress.
*
* @return boolean
*/
@Override
public boolean listenProgress() {
return true;
}
/**
* Reports progress in {@link StreamVariable} variant. Interrupts
*
* @see com.vaadin.server.StreamVariable#onProgress(com.vaadin.server.StreamVariable.StreamingProgressEvent)
*/
@Override
public void onProgress(final StreamingProgressEvent event) {
assertStateConsistency(fileUploadId, event.getFileName());
if (isUploadInterrupted()) {
publishUploadFailedAndFinishedEvent(fileUploadId);
return;
}
if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) {
interruptUploadDueToFileSizeQuotaExceeded(SizeConversionHelper.byteValueToReadableString(maxSize));
return;
}
publishUploadProgressEvent(fileUploadId, event.getBytesReceived(), event.getContentLength());
}
/**
* Upload finished for {@link StreamVariable} variant. Called only in good
* case.
*
* @see com.vaadin.server.StreamVariable#streamingFinished(com.vaadin.server.StreamVariable.StreamingEndEvent)
*/
@Override
public void streamingFinished(final StreamingEndEvent event) {
assertStateConsistency(fileUploadId, event.getFileName());
}
/**
* Upload failed for{@link StreamVariable} variant.
*
* @param event
* StreamingEndEvent
*/
@Override
public void streamingFailed(final StreamingErrorEvent event) {
assertStateConsistency(fileUploadId, event.getFileName());
if (!isUploadInterrupted()) {
interruptUploadDueToUploadFailed();
}
LOG.debug("Streaming of file {} failed due to following exception: {}", fileUploadId, event.getException());
publishUploadFailedAndFinishedEvent(fileUploadId);
}
/**
* Verify if upload process is interrupted
*
* @return boolean
*/
@Override
public boolean isInterrupted() {
return isUploadInterrupted();
}
}

View File

@@ -1,212 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.locks.Lock;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
import org.eclipse.hawkbit.repository.SizeConversionHelper;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.ByteStreams;
import com.vaadin.ui.Upload;
import com.vaadin.ui.Upload.FailedEvent;
import com.vaadin.ui.Upload.FailedListener;
import com.vaadin.ui.Upload.FinishedEvent;
import com.vaadin.ui.Upload.FinishedListener;
import com.vaadin.ui.Upload.ProgressListener;
import com.vaadin.ui.Upload.Receiver;
import com.vaadin.ui.Upload.StartedEvent;
import com.vaadin.ui.Upload.StartedListener;
import com.vaadin.ui.Upload.SucceededEvent;
import com.vaadin.ui.Upload.SucceededListener;
/**
* Vaadin Upload implementation to read and upload a file. One instance is used
* to handle all the uploads.
*
* The handler manages the output to the user and at the same time ensures that
* the upload does not exceed the configured max file size.
*
*/
public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
implements Receiver, SucceededListener, FailedListener, FinishedListener, ProgressListener, StartedListener {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(FileTransferHandlerVaadinUpload.class);
private final transient SoftwareModuleManagement softwareModuleManagement;
private final long maxSize;
private FileUploadId fileUploadId;
FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement,
final ArtifactManagement artifactManagement, final VaadinMessageSource i18n, final Lock uploadLock) {
super(artifactManagement, i18n, uploadLock);
this.maxSize = maxSize;
this.softwareModuleManagement = softwareManagement;
}
private synchronized FileUploadId setFileUploadId(final String fileName, final SoftwareModule softwareModule) {
this.fileUploadId = new FileUploadId(fileName, softwareModule);
return fileUploadId;
}
/**
* Upload started for {@link Upload} variant.
*
* @see com.vaadin.ui.Upload.StartedListener#uploadStarted(com.vaadin.ui.Upload.StartedEvent)
*/
@Override
public void uploadStarted(final StartedEvent event) {
// reset internal state here because instance is reused for next upload!
resetState();
final SoftwareModule softwareModule = getSelectedSoftwareModule();
final FileUploadId fupId = setFileUploadId(event.getFilename(), softwareModule);
if (getUploadState().isFileInUploadState(this.fileUploadId)) {
// actual interrupt will happen a bit late so setting the below
// flag
interruptUploadDueToDuplicateFile();
event.getUpload().interruptUpload();
} else {
publishUploadStarted(fupId);
if (RegexCharacterCollection.stringContainsCharacter(event.getFilename(), ILLEGAL_FILENAME_CHARACTERS)) {
LOG.debug("Filename contains illegal characters {} for upload {}", fupId.getFilename(), fupId);
interruptUploadDueToIllegalFilename();
event.getUpload().interruptUpload();
} else if (isFileAlreadyContainedInSoftwareModule(fupId, softwareModule)) {
LOG.debug("File {} already contained in Software Module {}", fupId.getFilename(),
softwareModule);
interruptUploadDueToDuplicateFile();
event.getUpload().interruptUpload();
}
}
}
private SoftwareModule getSelectedSoftwareModule() {
final Long lastSelectedSmId = getUploadState().getSmGridLayoutUiState().getSelectedEntityId();
return softwareModuleManagement.get(lastSelectedSmId)
.orElseThrow(() -> new IllegalStateException("SoftwareModul with unknown ID selected"));
}
/**
* Create stream for {@link Upload} variant.
*
* @see com.vaadin.ui.Upload.Receiver#receiveUpload(java.lang.String,
* java.lang.String)
*/
@Override
public OutputStream receiveUpload(final String fileName, final String mimeType) {
if (isUploadInterrupted()) {
return ByteStreams.nullOutputStream();
}
// we return the outputstream so we cannot close it here
@SuppressWarnings("squid:S2095")
final PipedOutputStream outputStream = new PipedOutputStream();
try {
PipedInputStream inputStream = new PipedInputStream(outputStream);
publishUploadProgressEvent(fileUploadId, 0, 0);
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
} catch (final IOException e) {
LOG.warn("Creating piped Stream failed!", e);
tryToCloseIOStream(outputStream);
// input stream is not created in case of an IOException
interruptUploadDueToUploadFailed();
publishUploadFailedAndFinishedEvent(fileUploadId);
return ByteStreams.nullOutputStream();
}
return outputStream;
}
/**
* Reports progress in {@link Upload} variant.
*
* @see com.vaadin.ui.Upload.ProgressListener#updateProgress(long, long)
*/
@Override
public void updateProgress(final long readBytes, final long contentLength) {
if (isUploadInterrupted()) {
publishUploadFailedAndFinishedEvent(fileUploadId);
return;
}
if (readBytes > maxSize || contentLength > maxSize) {
interruptUploadDueToFileSizeQuotaExceeded(SizeConversionHelper.byteValueToReadableString(maxSize));
return;
}
publishUploadProgressEvent(fileUploadId, readBytes, contentLength);
}
/**
*
* Upload sucessfull for {@link Upload} variant.
*
* @see com.vaadin.ui.Upload.SucceededListener#uploadSucceeded(com.vaadin.ui.Upload.SucceededEvent)
*/
@Override
public void uploadSucceeded(final SucceededEvent event) {
if (isUploadInterrupted()) {
// Upload interruption is delayed maybe another event is fired
// before
return;
}
assertStateConsistency(fileUploadId, event.getFilename());
}
/**
* Upload finished for {@link Upload} variant. Both for good and error
* variant.
*
* @see com.vaadin.ui.Upload.FinishedListener#uploadFinished(com.vaadin.ui.Upload.FinishedEvent)
*/
@Override
public void uploadFinished(final FinishedEvent event) {
// ignore this event
}
/**
* Upload failed for {@link Upload} variant.
*
* @see com.vaadin.ui.Upload.FailedListener#uploadFailed(com.vaadin.ui.Upload.FailedEvent)
*/
@Override
public void uploadFailed(final FailedEvent event) {
assertStateConsistency(fileUploadId, event.getFilename());
if (!isUploadInterrupted()) {
interruptUploadDueToUploadFailed();
}
LOG.debug("Upload of file {} failed due to following exception: {}", fileUploadId, event.getReason());
publishUploadFailedAndFinishedEvent(fileUploadId);
}
@Override
protected void resetState() {
super.resetState();
this.fileUploadId = null;
}
}

View File

@@ -1,92 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* The {@link FileUploadId} identifies a file that is uploaded for a
* {@link SoftwareModule}.
*
*/
public class FileUploadId implements Serializable {
private static final long serialVersionUID = 1L;
private final String filename;
private final Long softwareModuleId;
private final String softwareModuleName;
private final String softwareModuleVersion;
/**
* Creates a new {@link FileUploadId} instance.
*
* @param filename
* the name of the file
* @param softwareModule
* the {@link SoftwareModule} for which the file is uploaded
*/
public FileUploadId(final String filename, final SoftwareModule softwareModule) {
this.filename = filename;
this.softwareModuleId = softwareModule.getId();
this.softwareModuleName = softwareModule.getName();
this.softwareModuleVersion = softwareModule.getVersion();
}
public String getFilename() {
return filename;
}
public Long getSoftwareModuleId() {
return softwareModuleId;
}
public String getSoftwareModuleName() {
return softwareModuleName;
}
public String getSoftwareModuleVersion() {
return softwareModuleVersion;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileUploadId other = (FileUploadId) obj;
return Objects.equals(this.getFilename(), other.getFilename())
&& Objects.equals(this.getSoftwareModuleId(), other.getSoftwareModuleId())
&& Objects.equals(this.getSoftwareModuleName(), other.getSoftwareModuleName())
&& Objects.equals(this.getSoftwareModuleVersion(), other.getSoftwareModuleVersion());
}
@Override
public int hashCode() {
return Objects.hash(getFilename(), getSoftwareModuleId(), getSoftwareModuleName(), getSoftwareModuleVersion());
}
@Override
public String toString() {
return new StringBuilder(filename).append(":")
.append(HawkbitCommonUtil.getFormattedNameVersion(softwareModuleName, softwareModuleVersion))
.toString();
}
}

View File

@@ -1,193 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.Serializable;
/**
* Holds file and upload progress details.
*/
public class FileUploadProgress implements Serializable {
/**
* Status of a file upload.
*/
public enum FileUploadStatus {
/**
* An upload for a file has been started.
*/
UPLOAD_STARTED,
/**
* Progress changed for one file upload.
*/
UPLOAD_IN_PROGRESS,
/**
* Upload of one file failed.
*/
UPLOAD_FAILED,
/**
* One file upload succeeded.
*/
UPLOAD_SUCCESSFUL,
/**
* One file upload finished ()
*/
UPLOAD_FINISHED
}
private static final long serialVersionUID = 1L;
private final FileUploadId fileUploadId;
private long contentLength;
private long bytesRead;
private String failureReason;
private String filePath;
private final 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
*/
public FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus) {
this.fileUploadId = fileUploadId;
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.
*
* @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
* @param filePath
* the path of the file
*/
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus, final long bytesRead,
final long contentLength, final String filePath) {
this.fileUploadId = fileUploadId;
this.fileUploadStatus = fileUploadStatus;
this.contentLength = contentLength;
this.bytesRead = bytesRead;
this.filePath = filePath;
}
/**
* 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 failureReason
* the reason of the failed upload
*/
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus,
final String failureReason) {
this.fileUploadId = fileUploadId;
this.fileUploadStatus = fileUploadStatus;
this.failureReason = failureReason;
}
/**
* Getter for file upload ID
*
* @return FileUploadId
*/
public FileUploadId getFileUploadId() {
return fileUploadId;
}
/**
* Getter for file content length
*
* @return long
*/
public long getContentLength() {
return contentLength;
}
/**
* Getter for bytes read of the file
*
* @return long
*/
public long getBytesRead() {
return bytesRead;
}
/**
* Getter for failed reason for upload
* @return String
*/
public String getFailureReason() {
return failureReason;
}
/**
* Getter for file path
*
* @return String
*/
public String getFilePath() {
return filePath;
}
/**
* Get Status of a file upload
*
* @return FileUploadStatus
*/
public FileUploadStatus getFileUploadStatus() {
return fileUploadStatus;
}
}

View File

@@ -1,234 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.util.Collection;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.servlet.MultipartConfigElement;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.Html5File;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.dnd.FileDropHandler;
import com.vaadin.ui.dnd.FileDropTarget;
import com.vaadin.ui.dnd.event.FileDropEvent;
/**
* Container for drag and drop area in the upload view.
*/
public class UploadDropAreaLayout extends CustomComponent implements MasterEntityAwareComponent<ProxySoftwareModule> {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final UINotification uiNotification;
private final ArtifactUploadState artifactUploadState;
private final transient ArtifactManagement artifactManagement;
private final transient SoftwareModuleManagement softwareManagement;
private final transient MultipartConfigElement multipartConfigElement;
private final transient Lock uploadLock = new ReentrantLock();
private final UploadProgressButtonLayout uploadButtonLayout;
private VerticalLayout dropAreaLayout;
/**
* Creates a new {@link UploadDropAreaLayout} instance.
*
* @param uiDependencies
* the {@link CommonUiDependencies}
* @param artifactUploadState
* the {@link ArtifactUploadState} for state information
* @param multipartConfigElement
* the {@link MultipartConfigElement}
* @param softwareManagement
* the {@link SoftwareModuleManagement} for retrieving the
* {@link SoftwareModule}
* @param artifactManagement
* the {@link ArtifactManagement} for storing the uploaded
* artifacts
*/
public UploadDropAreaLayout(final CommonUiDependencies uiDependencies, final ArtifactUploadState artifactUploadState,
final MultipartConfigElement multipartConfigElement, final SoftwareModuleManagement softwareManagement,
final ArtifactManagement artifactManagement) {
this.i18n = uiDependencies.getI18n();
this.uiNotification = uiDependencies.getUiNotification();
this.artifactUploadState = artifactUploadState;
this.multipartConfigElement = multipartConfigElement;
this.softwareManagement = softwareManagement;
this.artifactManagement = artifactManagement;
this.uploadButtonLayout = new UploadProgressButtonLayout(i18n, uiDependencies.getEventBus(), artifactUploadState,
multipartConfigElement, artifactManagement, softwareManagement, uploadLock);
buildLayout();
}
private void buildLayout() {
dropAreaLayout = new VerticalLayout();
dropAreaLayout.setId(UIComponentIdProvider.UPLOAD_ARTIFACT_FILE_DROP_LAYOUT);
dropAreaLayout.setMargin(false);
dropAreaLayout.setSpacing(false);
dropAreaLayout.addStyleName("upload-drop-area-layout-info");
dropAreaLayout.setEnabled(false);
dropAreaLayout.setHeightUndefined();
final Label dropIcon = new Label(VaadinIcons.ARROW_DOWN.getHtml(), ContentMode.HTML);
dropIcon.addStyleName("drop-icon");
dropIcon.setWidth(null);
dropAreaLayout.addComponent(dropIcon);
final Label dropHereLabel = new Label(i18n.getMessage(UIMessageIdProvider.LABEL_DROP_AREA_UPLOAD));
dropHereLabel.setWidth(null);
dropAreaLayout.addComponent(dropHereLabel);
uploadButtonLayout.setWidth(null);
uploadButtonLayout.addStyleName("upload-button");
dropAreaLayout.addComponent(uploadButtonLayout);
new FileDropTarget<>(dropAreaLayout, new UploadFileDropHandler());
setCompositionRoot(dropAreaLayout);
}
/**
* Update the upload view on file drop
*
* @param masterEntity
* ProxySoftwareModule
*/
@Override
public void masterEntityChanged(final ProxySoftwareModule masterEntity) {
final Long masterEntityId = masterEntity != null ? masterEntity.getId() : null;
dropAreaLayout.setEnabled(masterEntityId != null);
uploadButtonLayout.updateMasterEntityFilter(masterEntityId);
}
/**
* Checks progress on file upload
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
uploadButtonLayout.onUploadChanged(fileUploadProgress);
}
/**
* Is called when view is shown to the user
*/
public void restoreState() {
uploadButtonLayout.restoreState();
}
/**
* Get file drop area layout
*
* @return VerticalLayout
*/
public VerticalLayout getDropAreaLayout() {
return dropAreaLayout;
}
/**
* Get File upload button layout
*
* @return UploadProgressButtonLayout
*/
public UploadProgressButtonLayout getUploadButtonLayout() {
return uploadButtonLayout;
}
private class UploadFileDropHandler implements FileDropHandler<VerticalLayout> {
private static final long serialVersionUID = 1L;
/**
* Validates the file drop events and triggers the upload
*
* @param event
* FileDropEvent
*/
@Override
public void drop(final FileDropEvent<VerticalLayout> event) {
if (validate(event)) {
// selected software module at the time of file drop is
// considered for upload
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
if (lastSelectedSmId != null) {
uploadFilesForSoftwareModule(event.getFiles(), lastSelectedSmId);
}
}
}
private void uploadFilesForSoftwareModule(final Collection<Html5File> files, final Long softwareModuleId) {
final SoftwareModule softwareModule = softwareManagement.get(softwareModuleId).orElse(null);
boolean duplicateFound = false;
for (final Html5File file : files) {
if (artifactUploadState.isFileInUploadState(file.getFileName(), softwareModule)) {
duplicateFound = true;
} else {
file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(),
multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement,
i18n, uploadLock));
}
}
if (duplicateFound) {
uiNotification.displayValidationError(i18n.getMessage("message.no.duplicateFiles"));
}
}
private boolean validate(final FileDropEvent<VerticalLayout> event) {
// check if drop is valid.If valid ,check if software module is
// selected.
if (!isFilesDropped(event)) {
uiNotification.displayValidationError(i18n.getMessage("message.drop.onlyFiles"));
return false;
}
return validateSoftwareModuleSelection();
}
private boolean isFilesDropped(final FileDropEvent<VerticalLayout> event) {
return event.getFiles() != null;
}
private boolean validateSoftwareModuleSelection() {
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
if (lastSelectedSmId == null) {
uiNotification.displayValidationError(i18n.getMessage("message.error.noSwModuleSelected"));
return false;
}
return true;
}
}
}

View File

@@ -1,96 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.OutputStream;
import com.vaadin.server.StreamVariable;
import com.vaadin.ui.Upload;
/**
* The {@link Upload} class has a bug.The lifecycle methods of the registered
* handler
* com.vaadin.ui.Upload.StartedListener#uploadStarted(com.vaadin.ui.Upload.StartedEvent)
* etc are called even the upload was interrupted. This bug is fixed in this
* class.
*
*/
public class UploadFixed extends Upload {
private static final long serialVersionUID = 1L;
private boolean uploadInterrupted;
/**
* Stops the file upload
*/
@Override
public void interruptUpload() {
super.interruptUpload();
uploadInterrupted = true;
}
@Override
protected StreamVariable getStreamVariable() {
return new StreamVariableFixed(super.getStreamVariable());
}
private class StreamVariableFixed implements StreamVariable {
private static final long serialVersionUID = 1L;
private final StreamVariable originalStreamVariable;
/**
* Constructor for StreamVariableFixed
*
* @param originalStreamVariable
* StreamVariable
*/
public StreamVariableFixed(final StreamVariable originalStreamVariable) {
this.originalStreamVariable = originalStreamVariable;
}
@Override
public boolean listenProgress() {
// this fixes the vaadin bug
return originalStreamVariable.listenProgress() && !uploadInterrupted;
}
@Override
public void onProgress(final StreamingProgressEvent event) {
originalStreamVariable.onProgress(event);
}
@Override
public boolean isInterrupted() {
return uploadInterrupted;
}
@Override
public OutputStream getOutputStream() {
return originalStreamVariable.getOutputStream();
}
@Override
public void streamingStarted(final StreamingStartEvent event) {
originalStreamVariable.streamingStarted(event);
}
@Override
public void streamingFinished(final StreamingEndEvent event) {
originalStreamVariable.streamingFinished(event);
}
@Override
public void streamingFailed(final StreamingErrorEvent event) {
originalStreamVariable.streamingFailed(event);
uploadInterrupted = false;
}
}
}

View File

@@ -1,210 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.util.concurrent.locks.Lock;
import javax.servlet.MultipartConfigElement;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.vaadin.spring.events.EventBus.UIEventBus;
import com.vaadin.ui.Button;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
import com.vaadin.ui.VerticalLayout;
/**
* Container for upload and progress button.
*/
public class UploadProgressButtonLayout extends VerticalLayout {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final ArtifactUploadState artifactUploadState;
private final transient ArtifactManagement artifactManagement;
private final transient SoftwareModuleManagement softwareModuleManagement;
private final transient MultipartConfigElement multipartConfigElement;
private final Upload upload;
private final transient Lock uploadLock;
private final UploadProgressInfoWindow uploadInfoWindow;
private Button uploadProgressButton;
/**
* Creates a new {@link UploadProgressButtonLayout} instance.
*
* @param i18n
* the {@link VaadinMessageSource}
* @param eventBus
* the {@link UIEventBus} for listening to ui events
* @param artifactUploadState
* the {@link ArtifactUploadState} for state information
* @param multipartConfigElement
* the {@link MultipartConfigElement}
* @param softwareManagement
* the {@link SoftwareModuleManagement} for retrieving the
* {@link SoftwareModule}
* @param artifactManagement
* the {@link ArtifactManagement} for storing the uploaded
* artifacts
* @param uploadLock
* A common upload lock that enforced sequential upload within an
* UI instance
*/
public UploadProgressButtonLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
final ArtifactUploadState artifactUploadState, final MultipartConfigElement multipartConfigElement,
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
final Lock uploadLock) {
this.artifactUploadState = artifactUploadState;
this.artifactManagement = artifactManagement;
this.uploadInfoWindow = new UploadProgressInfoWindow(i18n, artifactUploadState);
this.uploadInfoWindow.addCloseListener(event -> {
// ensure that the progress button is hidden when the progress
// window is closed and no more uploads running
if (artifactUploadState.areAllUploadsFinished()) {
hideUploadProgressButton();
}
});
this.i18n = i18n;
this.multipartConfigElement = multipartConfigElement;
this.softwareModuleManagement = softwareManagement;
this.upload = new UploadFixed();
this.uploadLock = uploadLock;
createComponents();
buildLayout();
}
/**
* Perform specific tasks based on the file upload status
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
final FileUploadProgress.FileUploadStatus uploadProgressEventType = fileUploadProgress.getFileUploadStatus();
switch (uploadProgressEventType) {
case UPLOAD_STARTED:
UI.getCurrent().access(() -> {
onStartOfUpload();
uploadInfoWindow.onUploadStarted(fileUploadProgress);
});
break;
case UPLOAD_FAILED:
case UPLOAD_SUCCESSFUL:
case UPLOAD_IN_PROGRESS:
UI.getCurrent().access(() -> uploadInfoWindow.updateUploadProgressInfoRowObject(fileUploadProgress));
break;
case UPLOAD_FINISHED:
UI.getCurrent().access(() -> {
onUploadFinished();
uploadInfoWindow.onUploadFinished();
});
break;
default:
throw new IllegalArgumentException("Enum " + FileUploadProgress.FileUploadStatus.class.getSimpleName()
+ " doesn't contain value " + uploadProgressEventType);
}
}
/**
* Enable the upload view after upload is finished
*
* @param masterEntityId
* Long
*/
public void updateMasterEntityFilter(final Long masterEntityId) {
upload.setEnabled(masterEntityId != null && artifactUploadState.areAllUploadsFinished());
}
private void createComponents() {
uploadProgressButton = SPUIComponentProvider.getButton(UIComponentIdProvider.UPLOAD_STATUS_BUTTON, "", "", "",
false, null, SPUIButtonStyleNoBorder.class);
uploadProgressButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
uploadProgressButton.addClickListener(event -> showUploadInfoWindow());
}
private void buildLayout() {
final FileTransferHandlerVaadinUpload uploadHandler = new FileTransferHandlerVaadinUpload(
multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n,
uploadLock);
upload.setButtonCaption(i18n.getMessage("upload.file"));
upload.setReceiver(uploadHandler);
upload.addSucceededListener(uploadHandler);
upload.addFailedListener(uploadHandler);
upload.addFinishedListener(uploadHandler);
upload.addProgressListener(uploadHandler);
upload.addStartedListener(uploadHandler);
upload.setId(UIComponentIdProvider.UPLOAD_BUTTON);
addComponent(upload);
setSizeFull();
setMargin(false);
}
/**
* Is called when view is shown to the user
*/
public void restoreState() {
if (artifactUploadState.areAllUploadsFinished()) {
artifactUploadState.clearUploadTempData();
hideUploadProgressButton();
upload.setEnabled(true);
} else if (artifactUploadState.isAtLeastOneUploadInProgress()) {
showUploadProgressButton();
}
}
private void onStartOfUpload() {
showUploadProgressButton();
}
/**
* Called for every finished (succeeded or failed) upload.
*/
private void onUploadFinished() {
if (artifactUploadState.areAllUploadsFinished()) {
hideUploadProgressButton();
upload.setEnabled(true);
artifactUploadState.clearUploadTempData();
}
}
/**
* Maximize the file upload view
*/
public void showUploadInfoWindow() {
uploadInfoWindow.maximizeWindow();
}
private void showUploadProgressButton() {
removeComponent(upload);
addComponent(uploadProgressButton);
}
private void hideUploadProgressButton() {
removeComponent(uploadProgressButton);
addComponent(upload);
}
}

View File

@@ -1,86 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.ProgressStatusIconSupplier;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.Grid;
import com.vaadin.ui.renderers.ProgressBarRenderer;
/**
* Grid for Upload Progress pop up info window.
*/
public class UploadProgressGrid extends Grid<ProxyUploadProgress> {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private static final String UPLOAD_PROGRESS_STATUS_ID = "uploadProgressStatus";
private static final String UPLOAD_PROGRESS_BAR_ID = "uploadProgressBar";
private static final String UPLOAD_PROGRESS_FILENAME_ID = "uploadProgressFileName";
private static final String UPLOAD_PROGRESS_SM_ID = "uploadProgressSm";
private static final String UPLOAD_PROGRESS_REASON_ID = "uploadProgressReason";
private final ProgressStatusIconSupplier<ProxyUploadProgress> progressStatusIconSupplier;
/**
* Constructor for UploadProgressGrid
*
* @param i18n
* VaadinMessageSource
*/
public UploadProgressGrid(final VaadinMessageSource i18n) {
this.i18n = i18n;
progressStatusIconSupplier = new ProgressStatusIconSupplier<>(i18n, ProxyUploadProgress::getStatus,
UIComponentIdProvider.UPLOAD_STATUS_LABEL_ID);
init();
}
private void init() {
setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_GRID);
addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID);
setSelectionMode(SelectionMode.NONE);
setSizeFull();
addColumns();
}
private void addColumns() {
GridComponentBuilder.addIconColumn(this, progressStatusIconSupplier::getLabel, UPLOAD_PROGRESS_STATUS_ID,
i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_STATUS));
addColumn(ProxyUploadProgress::getProgress, new ProgressBarRenderer()).setId(UPLOAD_PROGRESS_BAR_ID)
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_PROGRESS)).setExpandRatio(1);
GridComponentBuilder.addColumn(this, uploadProgress -> uploadProgress.getFileUploadId().getFilename())
.setId(UPLOAD_PROGRESS_FILENAME_ID)
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_FILENAME));
GridComponentBuilder
.addColumn(this,
uploadProgress -> HawkbitCommonUtil.getFormattedNameVersion(
uploadProgress.getFileUploadId().getSoftwareModuleName(),
uploadProgress.getFileUploadId().getSoftwareModuleVersion()))
.setId(UPLOAD_PROGRESS_SM_ID).setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_SOFTWARE_MODULE));
GridComponentBuilder.addColumn(this, ProxyUploadProgress::getReason).setId(UPLOAD_PROGRESS_REASON_ID)
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_REASON));
getColumns().forEach(col -> col.setSortable(false));
}
}

View File

@@ -1,251 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress.ProgressSatus;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.StringUtils;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.shared.ui.window.WindowMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
/**
* Window that shows the progress of all uploads.
*/
public class UploadProgressInfoWindow extends Window {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final ArtifactUploadState artifactUploadState;
private final UploadProgressGrid uploadProgressGrid;
private final VerticalLayout mainLayout;
private Label windowCaption;
private Button closeButton;
private final List<ProxyUploadProgress> uploads;
UploadProgressInfoWindow(final VaadinMessageSource i18n, final ArtifactUploadState artifactUploadState) {
this.i18n = i18n;
this.artifactUploadState = artifactUploadState;
setPopupProperties();
createStatusPopupHeaderComponents();
mainLayout = new VerticalLayout();
mainLayout.setSpacing(Boolean.TRUE);
mainLayout.setSizeUndefined();
setPopupSizeInMinMode();
uploads = new ArrayList<>();
uploadProgressGrid = new UploadProgressGrid(i18n);
uploadProgressGrid.setItems(uploads);
mainLayout.addComponents(getCaptionLayout(), uploadProgressGrid);
mainLayout.setExpandRatio(uploadProgressGrid, 1.0F);
setContent(mainLayout);
}
/**
* Updates the status of each file uploaded in the grid view
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void updateUploadProgressInfoRowObject(final FileUploadProgress fileUploadProgress) {
final FileUploadId fileUploadId = fileUploadProgress.getFileUploadId();
final ProxyUploadProgress gridUploadItem = uploads.stream()
.filter(upload -> upload.getFileUploadId().equals(fileUploadId)).findAny()
.orElse(new ProxyUploadProgress());
gridUploadItem.setStatus(getStatusRepresentaion(fileUploadProgress.getFileUploadStatus()));
gridUploadItem.setReason(getFailureReason(fileUploadId));
final long bytesRead = fileUploadProgress.getBytesRead();
final long fileSize = fileUploadProgress.getContentLength();
if (bytesRead > 0 && fileSize > 0) {
gridUploadItem.setProgress((double) bytesRead / (double) fileSize);
}
if (gridUploadItem.getFileUploadId() == null) {
gridUploadItem.setFileUploadId(fileUploadId);
uploads.add(gridUploadItem);
}
uploadProgressGrid.getDataProvider().refreshItem(gridUploadItem);
}
private static ProgressSatus getStatusRepresentaion(final FileUploadStatus uploadStatus) {
if (uploadStatus == FileUploadStatus.UPLOAD_FAILED) {
return ProgressSatus.FAILED;
} else if (uploadStatus == FileUploadStatus.UPLOAD_SUCCESSFUL) {
return ProgressSatus.FINISHED;
} else {
return ProgressSatus.INPROGRESS;
}
}
/**
* Returns the failure reason for the provided fileUploadId or an empty
* string but never <code>null</code>.
*
* @param fileUploadId
* @return the failure reason or an empty String.
*/
private String getFailureReason(final FileUploadId fileUploadId) {
String failureReason = "";
if (artifactUploadState.getFileUploadProgress(fileUploadId) != null) {
failureReason = artifactUploadState.getFileUploadProgress(fileUploadId).getFailureReason();
}
if (StringUtils.isEmpty(failureReason)) {
return "";
}
return failureReason;
}
/**
* Starts the file upload process and maximize the upload view
*
* @param fileUploadProgress
* FileUploadProgress
*/
public void onUploadStarted(final FileUploadProgress fileUploadProgress) {
updateUploadProgressInfoRowObject(fileUploadProgress);
if (isWindowNotAlreadyAttached()) {
maximizeWindow();
}
}
private boolean isWindowNotAlreadyAttached() {
return !UI.getCurrent().getWindows().contains(this);
}
private void restoreState() {
uploads.clear();
for (final FileUploadProgress fileUploadProgress : artifactUploadState
.getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
updateUploadProgressInfoRowObject(fileUploadProgress);
}
}
private void setPopupProperties() {
setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_ID);
addStyleName(SPUIStyleDefinitions.UPLOAD_INFO);
setResizable(false);
setDraggable(true);
setClosable(false);
setModal(true);
}
private HorizontalLayout getCaptionLayout() {
final HorizontalLayout captionLayout = new HorizontalLayout();
captionLayout.setSizeFull();
captionLayout.setHeight("36px");
captionLayout.addComponents(windowCaption, closeButton);
captionLayout.setExpandRatio(windowCaption, 1.0F);
captionLayout.addStyleName("v-window-header");
return captionLayout;
}
private void createStatusPopupHeaderComponents() {
windowCaption = new Label(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_POPUP));
closeButton = getCloseButton();
}
private void openWindow() {
UI.getCurrent().addWindow(this);
center();
}
protected void maximizeWindow() {
openWindow();
restoreState();
artifactUploadState.setStatusPopupMinimized(false);
}
private void minimizeWindow() {
artifactUploadState.setStatusPopupMinimized(true);
closeWindow();
if (artifactUploadState.areAllUploadsFinished()) {
cleanupStates();
}
}
/**
* Called for every finished (succeeded or failed) upload.
*/
public void onUploadFinished() {
if (artifactUploadState.areAllUploadsFinished() && artifactUploadState.isStatusPopupMinimized()) {
if (artifactUploadState.getFilesInFailedState().isEmpty()) {
cleanupStates();
closeWindow();
} else {
maximizeWindow();
}
}
}
private void cleanupStates() {
uploads.clear();
artifactUploadState.clearUploadTempData();
}
private void setPopupSizeInMinMode() {
mainLayout.setWidth(900, Unit.PIXELS);
mainLayout.setHeight(510, Unit.PIXELS);
}
private Button getCloseButton() {
final Button closeBtn = SPUIComponentProvider.getButton(
UIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, VaadinIcons.CLOSE,
SPUIButtonStyleNoBorder.class);
closeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
closeBtn.addClickListener(event -> onClose());
return closeBtn;
}
private void onClose() {
if (artifactUploadState.areAllUploadsFinished()) {
cleanupStates();
closeWindow();
} else {
minimizeWindow();
}
}
private void closeWindow() {
setWindowMode(WindowMode.NORMAL);
setPopupSizeInMinMode();
close();
}
}

View File

@@ -1,127 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.autoconfigure;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.push.HawkbitEventPermissionChecker;
import org.eclipse.hawkbit.ui.push.HawkbitEventProvider;
import org.eclipse.hawkbit.ui.push.UIEventPermissionChecker;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.vaadin.spring.annotation.EnableVaadinExtensions;
import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.spring.events.annotation.EnableEventBus;
import com.vaadin.spring.annotation.UIScope;
/**
* The Management UI auto configuration.
*/
@Configuration
@EnableVaadinExtensions
@EnableEventBus
@ConditionalOnClass(MgmtUiConfiguration.class)
@Import(MgmtUiConfiguration.class)
public class MgmtUiAutoConfiguration {
@Bean
@ConditionalOnMissingBean
RedirectController uiRedirectController() {
return new RedirectController();
}
/**
* A message source bean to add distributed message sources.
*
* @return the message bean.
*/
@Bean(name = "messageSource")
DistributedResourceBundleMessageSource messageSource() {
return new DistributedResourceBundleMessageSource();
}
/**
* A event provider bean which hold the supported events for the UI.
*
* @return the provider bean
*/
@Bean
@ConditionalOnMissingBean
UIEventProvider eventProvider() {
return new HawkbitEventProvider();
}
/**
* A event permission checker bean which verifies supported events for the
* UI.
*
* @return the permission checker bean
*/
@Bean
@ConditionalOnMissingBean
UIEventPermissionChecker eventPermissionChecker(final SpPermissionChecker permChecker) {
return new HawkbitEventPermissionChecker(permChecker);
}
/**
* Bean for creating a singleton instance of the {@link SpringContextHolder}
*
* @return the singleton instance of the {@link SpringContextHolder}
*/
@Bean
SpringContextHolder springContextHolder() {
return SpringContextHolder.getInstance();
}
/**
* The UI scoped event push strategy. Session scope is necessary, that every
* UI has an own strategy.
*
* @param applicationContext
* the context to add the listener to
* @param executorService
* the general scheduler service
* @param eventBus
* the ui event bus
* @param eventProvider
* the event provider
* @param eventPermissionChecker
* the event permission checker
* @param uiProperties
* the ui properties
* @return the push strategy bean
*/
@Bean
@ConditionalOnMissingBean
@UIScope
EventPushStrategy eventPushStrategy(final ConfigurableApplicationContext applicationContext,
final ScheduledExecutorService executorService, final UIEventBus eventBus,
final UIEventProvider eventProvider, final UIEventPermissionChecker eventPermissionChecker,
final UiProperties uiProperties) {
final DelayedEventBusPushStrategy delayedEventBusPushStrategy = new DelayedEventBusPushStrategy(executorService,
eventBus, eventProvider, eventPermissionChecker, uiProperties.getEvent().getPush().getDelay());
applicationContext.addApplicationListener(delayedEventBusPushStrategy);
return delayedEventBusPushStrategy;
}
}

View File

@@ -1,31 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.autoconfigure;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Redirects for convenience. hawkBit's management UI is by default not
* listening on / but on /UI.
*
*/
@Controller
public class RedirectController {
/**
* @return redirect to the Management UI
*/
@GetMapping("/")
public ModelAndView home() {
return new ModelAndView("redirect:/UI/");
}
}

View File

@@ -1,257 +0,0 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.autoconfigure;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.security.DosFilter;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.util.ObjectUtils;
import org.vaadin.spring.http.HttpService;
import org.vaadin.spring.security.annotation.EnableVaadinSharedSecurity;
import org.vaadin.spring.security.config.VaadinSharedSecurityConfiguration;
import org.vaadin.spring.security.shared.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.shared.VaadinUrlAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import java.util.Arrays;
/**
* {@link WebSecurityConfigurer} for external (management) access.
*/
@Configuration
@EnableWebSecurity
@EnableVaadinSharedSecurity
@ConditionalOnClass(MgmtUiConfiguration.class)
public class UISecurityConfigurationAdapter {
private static final Logger LOG = LoggerFactory.getLogger(UISecurityConfigurationAdapter.class);
private static final int DOS_FILTER_ORDER = -200;
@Autowired
private HawkbitSecurityProperties hawkbitSecurityProperties;
/**
* Filter to protect the hawkBit management UI against to many requests.
*
* @param securityProperties for filter configuration
* @return the spring filter registration bean for registering a denial
* of service protection filter in the filter chain
*/
@Bean
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true)
public FilterRegistrationBean<DosFilter> dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
final HawkbitSecurityProperties.Dos.Filter filterProperties = securityProperties.getDos().getUiFilter();
final HawkbitSecurityProperties.Clients clientProperties = securityProperties.getClients();
final FilterRegistrationBean<DosFilter> filterRegBean = new FilterRegistrationBean<>();
filterRegBean.setFilter(new DosFilter(null, filterProperties.getMaxRead(),
filterProperties.getMaxWrite(), filterProperties.getWhitelist(), clientProperties.getBlacklist(),
clientProperties.getRemoteIpHeader()));
// All URLs that can be called anonymous
filterRegBean.setUrlPatterns(Arrays.asList("/UI/login", "/UI/login/*", "/UI/logout", "/UI/logout/*"));
filterRegBean.setOrder(DOS_FILTER_ORDER);
filterRegBean.setName("dosMgmtUiFilter");
return filterRegBean;
}
@Bean
AuthenticationManager authenticationManager(final AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
/**
* Overwriting VaadinAuthenticationSuccessHandler of default
* VaadinSharedSecurityConfiguration
*
* @return the vaadin success authentication handler
*/
@Primary
@Bean(name = VaadinSharedSecurityConfiguration.VAADIN_AUTHENTICATION_SUCCESS_HANDLER_BEAN)
public VaadinAuthenticationSuccessHandler redirectSaveHandler(final HttpService httpService,
final VaadinRedirectStrategy redirectStrategy) {
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(
httpService, redirectStrategy, "/UI/");
handler.setTargetUrlParameter("r");
return handler;
}
/**
* Listener to redirect to login page after session timeout. Close the
* vaadin session, because it's is not possible to redirect in
* atmosphere.
*
* @return the servlet listener.
*/
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
}
@Bean
@Order(400)
protected SecurityFilterChain filterChainUI(
final HttpSecurity http,
@Autowired(required = false)
final OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService,
@Autowired(required = false)
final AuthenticationSuccessHandler authenticationSuccessHandler,
final LogoutHandler logoutHandler,
final LogoutSuccessHandler logoutSuccessHandler)
throws Exception {
final boolean enableOidc = oidcUserService != null && authenticationSuccessHandler != null;
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here
// because we bound the vaadin application to /UI and not to root,
// described in vaadin-forum:
// https://vaadin.com/forum#!/thread/3200565.
HttpSecurity httpSec;
if (enableOidc) {
httpSec = http.requestMatchers().antMatchers("/**/UI/**", "/**/oauth2/**").and();
} else {
httpSec = http.antMatcher("/**/UI/**");
}
// disable as CSRF is handled by Vaadin
httpSec.csrf(AbstractHttpConfigurer::disable);
// allow same origin X-Frame-Options for correct file download under
// Safari
httpSec.headers().frameOptions().sameOrigin();
if (hawkbitSecurityProperties.isRequireSsl()) {
httpSec = httpSec.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
} else {
LOG.info(
"""
******************
** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **
******************""");
}
if (!ObjectUtils.isEmpty(hawkbitSecurityProperties.getContentSecurityPolicy())) {
httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
}
// UI
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
.authenticated();
if (enableOidc) {
// OIDC
httpSec.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
.successHandler(authenticationSuccessHandler).and().oauth2Client();
} else {
// UI login / Basic auth
httpSec.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login"));
}
// UI logout
httpSec.logout().logoutUrl("/UI/logout*").addLogoutHandler(logoutHandler)
.logoutSuccessHandler(logoutSuccessHandler);
return httpSec.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// No security for static content
return (web) -> web.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
}
/**
* Configuration that defines the {@link AccessDecisionManager} bean for
* UI method security used by the Vaadin Servlet. Notice: we can not use
* the top-level method security configuration because
* AdviceMode.ASPECTJ is not supported.
*/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
@ConditionalOnClass(MgmtUiConfiguration.class)
static class UIMethodSecurity extends GlobalMethodSecurityConfiguration {
@Bean(name = VaadinSharedSecurityConfiguration.ACCESS_DECISION_MANAGER_BEAN)
@Override
protected AccessDecisionManager accessDecisionManager() {
return super.accessDecisionManager();
}
}
/**
* After a successful login on the UI we need to ensure to create the tenant
* meta data within SP.
*/
class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
@Autowired
private SystemManagement systemManagement;
@Autowired
private SystemSecurityContext systemSecurityContext;
public TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(final HttpService http,
final VaadinRedirectStrategy redirectStrategy, final String defaultTargetUrl) {
super(http, redirectStrategy, defaultTargetUrl);
}
@Override
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, getTenantFrom(authentication));
super.onAuthenticationSuccess(authentication);
}
private static String getTenantFrom(final Authentication authentication) {
final Object details = authentication.getDetails();
if (details instanceof TenantAwareAuthenticationDetails) {
return ((TenantAwareAuthenticationDetails) details).getTenant();
}
throw new InsufficientAuthenticationException("Authentication details/tenant info are not specified!");
}
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
/**
* Window controller for entity creations.
*
* @param <T>
* Type of proxy entity
* @param <E>
* Second type of proxy entity
* @param <R>
* Type of repository entity
*/
public abstract class AbstractAddEntityWindowController<T, E, R> extends AbstractEntityWindowController<T, E, R> {
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
protected AbstractAddEntityWindowController(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
}
@Override
protected String getPersistSuccessMessageKey() {
return "message.save.success";
}
@Override
protected String getPersistFailureMessageKey() {
return "message.save.fail";
}
@Override
protected EntityModifiedEventPayload createModifiedEventPayload(final R entity) {
return new EntityModifiedEventPayload(EntityModifiedEventType.ENTITY_ADDED, getParentEntityClass(),
getEntityClass(), getId(entity));
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
/**
* Window controller for named entity creations.
*
* @param <T>
* Type of proxy entity
* @param <E>
* Second type of proxy entity
* @param <R>
* Type of repository entity
*/
public abstract class AbstractAddNamedEntityWindowController<T, E extends ProxyNamedEntity, R extends NamedEntity>
extends AbstractAddEntityWindowController<T, E, R> {
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
protected AbstractAddNamedEntityWindowController(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
}
@Override
protected String getDisplayableName(final R entity) {
return entity.getName();
}
@Override
protected String getDisplayableNameForFailedMessage(final E entity) {
return entity.getName();
}
@Override
protected Long getId(final R entity) {
return entity.getId();
}
}

View File

@@ -1,92 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.Component;
import com.vaadin.ui.Window;
/**
* Builder for abstract entity window
*
* @param <T>
* Generic type entity
*/
public abstract class AbstractEntityWindowBuilder<T> {
protected final CommonUiDependencies uiDependencies;
protected AbstractEntityWindowBuilder(final CommonUiDependencies uiDependencies) {
this.uiDependencies = uiDependencies;
}
protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController<T, ?, ?> controller) {
return getWindowForEntity(null, controller);
}
protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController<T, ?, ?> controller,
final Component windowContent) {
return getWindowForEntity(null, controller, windowContent);
}
protected CommonDialogWindow getWindowForEntity(final T proxyEntity,
final AbstractEntityWindowController<T, ?, ?> controller) {
return getWindowForEntity(proxyEntity, controller, controller.getLayout().getRootComponent());
}
protected CommonDialogWindow getWindowForEntity(final T proxyEntity,
final AbstractEntityWindowController<T, ?, ?> controller, final Component windowContent) {
controller.populateWithData(proxyEntity);
final CommonDialogWindow window = createWindow(windowContent, controller.getSaveDialogCloseListener());
controller.getLayout().addValidationListener(window::setSaveButtonEnabled);
return window;
}
protected CommonDialogWindow createWindow(final Component content,
final SaveDialogCloseListener saveDialogCloseListener) {
return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).id(getWindowId()).content(content)
.i18n(uiDependencies.getI18n()).helpLink(getHelpLink()).saveDialogCloseListener(saveDialogCloseListener)
.buildCommonDialogWindow();
}
protected abstract String getWindowId();
/**
* Gets the add window
*
* @return window
*/
public abstract Window getWindowForAdd();
/**
* Gets the update window
*
* @param entity
* Generic type entity
*
* @return window
*/
public abstract Window getWindowForUpdate(final T entity);
protected String getHelpLink() {
// can be overriden to provide help link to documentation
return null;
}
protected VaadinMessageSource getI18n() {
return uiDependencies.getI18n();
}
}

View File

@@ -1,206 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.Objects;
import javax.validation.ConstraintViolationException;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.event.CommandTopics;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EventTopics;
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vaadin.spring.events.EventBus.UIEventBus;
/**
* Controller for abstract entity window
*
* @param <T>
* Type of proxy entity
* @param <E>
* Second type of proxy entity
* @param <R>
* Type of repository entity
*/
public abstract class AbstractEntityWindowController<T, E, R> {
private static final Logger LOG = LoggerFactory.getLogger(AbstractEntityWindowController.class);
private final CommonUiDependencies uiDependencies;
/**
* Constructor.
*
* @param uiDependencies
* the {@link CommonUiDependencies}
*/
protected AbstractEntityWindowController(final CommonUiDependencies uiDependencies) {
this.uiDependencies = uiDependencies;
}
/**
* Populate entity with data
*
* @param proxyEntity
* Generic type entity
*/
public void populateWithData(final T proxyEntity) {
getLayout().setEntity(buildEntityFromProxy(proxyEntity));
adaptLayout(proxyEntity);
}
/**
* @return layout
*/
public abstract EntityWindowLayout<E> getLayout();
protected abstract E buildEntityFromProxy(final T proxyEntity);
protected void adaptLayout(final T proxyEntity) {
// can be overriden to adapt layout components (e.g. disable/enable
// fields, adapt bindings, etc.)
}
/**
* @return Save dialog close listener
*/
public SaveDialogCloseListener getSaveDialogCloseListener() {
return new SaveDialogCloseListener() {
@Override
public void saveOrUpdate() {
persistEntity(getLayout().getEntity());
}
@Override
public boolean canWindowSaveOrUpdate() {
return isEntityValid(getLayout().getEntity());
}
@Override
public boolean canWindowClose() {
return closeWindowAfterSave();
}
};
}
protected void persistEntity(final E entity) {
try {
final R createdEntity = persistEntityInRepository(entity);
handleEntityPersistedSuccessfully(createdEntity);
selectPersistedEntity(createdEntity);
} catch (final ConstraintViolationException | EntityNotFoundException | EntityReadOnlyException ex) {
handleEntityPersistFailed(entity, ex);
} finally {
postPersist();
}
}
protected abstract R persistEntityInRepository(E entity);
protected void handleEntityPersistedSuccessfully(final R persistedEntity) {
displaySuccess(getPersistSuccessMessageKey(), getDisplayableName(persistedEntity));
publishModifiedEvent(createModifiedEventPayload(persistedEntity));
}
protected void handleEntityPersistFailed(final E entity, final RuntimeException ex) {
final String name = getDisplayableNameForFailedMessage(entity);
final String id = Objects.toString(entity);
final String type = getEntityClass().getSimpleName();
LOG.warn("Persist of entity name:{}, id:{}, type:{} failed in UI with reason: {}", name, id, type,
ex.getMessage());
displayWarning(getPersistFailureMessageKey(), name);
}
protected abstract EntityModifiedEventPayload createModifiedEventPayload(final R entity);
protected abstract Long getId(R entity);
protected abstract String getDisplayableNameForFailedMessage(E entity);
protected abstract String getDisplayableName(R entity);
protected abstract String getPersistSuccessMessageKey();
protected abstract String getPersistFailureMessageKey();
protected abstract Class<? extends ProxyIdentifiableEntity> getEntityClass();
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
return null;
}
protected void selectPersistedEntity(final R entity) {
// entity is not selected by default
}
protected void postPersist() {
// empty default implementation
}
protected abstract boolean isEntityValid(final E entity);
protected boolean closeWindowAfterSave() {
return true;
}
protected VaadinMessageSource getI18n() {
return uiDependencies.getI18n();
}
protected EntityFactory getEntityFactory() {
return uiDependencies.getEntityFactory();
}
protected UIEventBus getEventBus() {
return uiDependencies.getEventBus();
}
protected UINotification getUiNotification() {
return uiDependencies.getUiNotification();
}
protected void displaySuccess(final String messageKey, final Object... args) {
getUiNotification().displaySuccess(getI18n().getMessage(messageKey, args));
}
protected void displayValidationError(final String messageKey, final Object... args) {
getUiNotification().displayValidationError(getI18n().getMessage(messageKey, args));
}
protected void displayWarning(final String messageKey, final Object... args) {
getUiNotification().displayWarning(getI18n().getMessage(messageKey, args));
}
protected void publishModifiedEvent(final EntityModifiedEventPayload eventPayload) {
getEventBus().publish(EventTopics.ENTITY_MODIFIED, this, eventPayload);
}
protected void publishSelectionEvent(final SelectionChangedEventPayload<E> eventPayload) {
getEventBus().publish(CommandTopics.SELECT_GRID_ENTITY, this, eventPayload);
}
}

View File

@@ -1,55 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.Optional;
import java.util.function.Consumer;
import com.vaadin.data.Binder;
/**
* Abstract class for entity window layout
*
* @param <T>
* Generic type entity
*/
public abstract class AbstractEntityWindowLayout<T> implements EntityWindowLayout<T> {
protected final Binder<T> binder;
protected Consumer<Boolean> validationCallback;
protected AbstractEntityWindowLayout() {
this.binder = new Binder<>();
}
@Override
public void setEntity(final T proxyEntity) {
binder.setBean(proxyEntity);
}
@Override
public T getEntity() {
return binder.getBean();
}
@Override
public void addValidationListener(final Consumer<Boolean> validationCallback) {
binder.addStatusChangeListener(event -> validationCallback.accept(event.getBinder().isValid()));
this.validationCallback = validationCallback;
}
/**
* @return Validation callback event
*/
public Optional<Consumer<Boolean>> getValidationCallback() {
return Optional.ofNullable(validationCallback);
}
}

View File

@@ -1,158 +0,0 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.util.StringUtils;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewBeforeLeaveEvent;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.VerticalLayout;
/**
* Abstract class managing event listeners aware layouts.
*
*/
public abstract class AbstractEventListenersAwareView extends VerticalLayout implements View, ViewNameAware {
private static final long serialVersionUID = 1L;
// directly taken from Vaadin Navigator for consistency
private static final String DEFAULT_STATE_PARAMETER_SEPARATOR = "&";
private static final String DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR = "=";
private final transient List<EventListenersAwareLayout> eventAwareLayouts = new ArrayList<>();
private boolean initial;
/**
* Adds event aware layout.
*
* @param eventAwareLayout
* event aware layout to add
*/
protected void addEventAwareLayout(final EventListenersAwareLayout eventAwareLayout) {
if (eventAwareLayout != null) {
eventAwareLayouts.add(eventAwareLayout);
}
}
/**
* Adds a list of event aware layouts.
*
* @param eventAwareLayouts
* event aware layouts to add
*/
protected void addEventAwareLayouts(final Collection<EventListenersAwareLayout> eventAwareLayouts) {
eventAwareLayouts.forEach(this::addEventAwareLayout);
}
@PostConstruct
protected void init() {
buildLayout();
initial = true;
}
/**
* Builds view layout.
*
*/
protected abstract void buildLayout();
@Override
public void enter(final ViewChangeEvent event) {
subscribeListeners();
if (initial) {
restoreState();
initial = false;
} else {
updateLayoutsOnViewEnter();
}
if (StringUtils.hasText(event.getParameters())) {
handleStateParams(parseStateParameters(event.getParameters()));
}
}
private static Map<String, String> parseStateParameters(final String urlParams) {
return Arrays.stream(urlParams.split(DEFAULT_STATE_PARAMETER_SEPARATOR)).map(paramPair -> {
final String[] keyValue = paramPair.split(DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR, 2);
if (keyValue.length == 2) {
return new AbstractMap.SimpleEntry<>(keyValue[0], keyValue[1]);
}
return null;
}).filter(Objects::nonNull)
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
}
/**
* Subscribes all listeners of added event aware layouts to event bus.
*
*/
protected void subscribeListeners() {
eventAwareLayouts.forEach(EventListenersAwareLayout::subscribeListeners);
}
/**
* Restores session state of added event aware layouts.
*
*/
protected void restoreState() {
eventAwareLayouts.forEach(EventListenersAwareLayout::restoreState);
}
/**
* Handles state url parameters of added event aware layouts.
*
* @param stateParams
* map of view state url parameters
*/
protected void handleStateParams(final Map<String, String> stateParams) {
eventAwareLayouts.forEach(layout -> layout.handleStateParameters(stateParams));
}
/**
* Called on view enter for added event aware layouts to update their state.
*
*/
protected void updateLayoutsOnViewEnter() {
eventAwareLayouts.forEach(EventListenersAwareLayout::onViewEnter);
}
@Override
public void beforeLeave(final ViewBeforeLeaveEvent event) {
unsubscribeListeners();
event.navigate();
}
/**
* Unsubscribes all listeners of added event aware layouts to event bus.
*
*/
protected void unsubscribeListeners() {
eventAwareLayouts.forEach(EventListenersAwareLayout::unsubscribeListeners);
}
@PreDestroy
public void destroy() {
unsubscribeListeners();
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
/**
* Window controller for entity updates.
*
* @param <T>
* Type of proxy entity
* @param <E>
* Second type of proxy entity
* @param <R>
* Type of repository entity
*/
public abstract class AbstractUpdateEntityWindowController<T, E, R> extends AbstractEntityWindowController<T, E, R> {
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
protected AbstractUpdateEntityWindowController(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
}
@Override
protected String getPersistSuccessMessageKey() {
return "message.update.success";
}
@Override
protected String getPersistFailureMessageKey() {
return "message.deleted.or.notAllowed";
}
@Override
protected EntityModifiedEventPayload createModifiedEventPayload(final R entity) {
return new EntityModifiedEventPayload(EntityModifiedEventType.ENTITY_UPDATED, getParentEntityClass(),
getEntityClass(), getId(entity));
}
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
/**
* Window controller for entity updates.
*
* @param <T>
* Type of proxy entity
* @param <E>
* Second type of proxy entity
* @param <R>
* Type of repository entity
*/
public abstract class AbstractUpdateNamedEntityWindowController<T, E extends ProxyNamedEntity, R extends NamedEntity>
extends AbstractUpdateEntityWindowController<T, E, R> {
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
protected AbstractUpdateNamedEntityWindowController(final CommonUiDependencies uiDependencies) {
super(uiDependencies);
}
@Override
protected String getDisplayableName(final R entity) {
return entity.getName();
}
@Override
protected String getDisplayableNameForFailedMessage(final E entity) {
return entity.getName();
}
@Override
protected Long getId(final R entity) {
return entity.getId();
}
}

View File

@@ -1,318 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.StringUtils;
import com.vaadin.event.ShortcutAction.KeyCode;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Link;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
/**
*
* Table pop-up-windows including a minimize and close icon in the upper right
* corner and a save and cancel button at the bottom. Is not intended to reuse.
*
*/
public class CommonDialogWindow extends Window {
private static final long serialVersionUID = 1L;
private final VaadinMessageSource i18n;
private final VerticalLayout mainLayout;
private final String caption;
private final Component content;
private final String helpLink;
private final ConfirmStyle confirmStyle;
private final Class<? extends SPUIButtonDecorator> buttonDecorator;
private Button confirmButton;
private Button cancelButton;
private HorizontalLayout buttonsLayout;
private Label mandatoryLabel;
private final ClickListener cancelButtonClickListener;
private final ClickListener closeClickListener;
private transient SaveDialogCloseListener closeListener;
/**
* Different kinds of confirm buttons
*/
public enum ConfirmStyle {
SAVE, OK, CONFIRM, NEXT
}
/**
* Constructor
*
* @param caption
* the caption
* @param content
* the content
* @param helpLink
* the helpLinks
* @param closeListener
* the saveDialogCloseListener
* @param cancelButtonClickListener
* the cancelButtonClickListener
* @param confirmStyle
* what kind of button is used
* @param buttonDecorator
* to style the confirm and cancel buttons
* @param i18n
* internationalization
*/
public CommonDialogWindow(final String caption, final Component content, final String helpLink,
final SaveDialogCloseListener closeListener, final ClickListener cancelButtonClickListener,
final ConfirmStyle confirmStyle, final Class<? extends SPUIButtonDecorator> buttonDecorator,
final VaadinMessageSource i18n) {
this.caption = caption;
this.content = content;
this.helpLink = helpLink;
this.closeListener = closeListener;
this.cancelButtonClickListener = cancelButtonClickListener;
this.confirmStyle = confirmStyle;
this.buttonDecorator = buttonDecorator;
this.i18n = i18n;
this.mainLayout = new VerticalLayout();
this.closeClickListener = this::onCloseEvent;
init();
}
private void onCloseEvent(final ClickEvent clickEvent) {
if (!clickEvent.getButton().equals(confirmButton)) {
close();
return;
}
if (!closeListener.canWindowSaveOrUpdate()) {
return;
}
closeListener.saveOrUpdate();
if (closeListener.canWindowClose()) {
close();
}
}
@Override
public void close() {
super.close();
this.confirmButton.setEnabled(false);
}
private final void init() {
mainLayout.setMargin(false);
mainLayout.setSpacing(false);
if (content instanceof GridLayout) {
addStyleName("marginTop");
}
if (content != null) {
mainLayout.addComponent(content);
mainLayout.setExpandRatio(content, 1.0F);
}
createMandatoryLabel();
final HorizontalLayout buttonLayout = createActionButtonsLayout();
mainLayout.addComponent(buttonLayout);
mainLayout.setComponentAlignment(buttonLayout, Alignment.TOP_CENTER);
setCaptionAsHtml(false);
setCaption(caption);
setContent(mainLayout);
setResizable(false);
center();
setModal(true);
addStyleName("fontsize");
}
protected void addCloseListenerForSaveButton() {
confirmButton.addClickListener(closeClickListener);
}
protected void addCloseListenerForCancelButton() {
cancelButton.addClickListener(closeClickListener);
}
private HorizontalLayout createActionButtonsLayout() {
buttonsLayout = new HorizontalLayout();
buttonsLayout.setSizeFull();
buttonsLayout.addStyleName("actionButtonsMargin");
createSaveButton();
createCancelButton();
addHelpLink();
return buttonsLayout;
}
private void createMandatoryLabel() {
mandatoryLabel = new Label(i18n.getMessage("label.mandatory.field"));
mandatoryLabel.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR + " " + ValoTheme.LABEL_TINY);
mainLayout.addComponent(mandatoryLabel);
}
/**
* Hide the line that explains the mandatory decorator
*
*/
public void hideMandatoryExplanation() {
if (mandatoryLabel != null) {
mainLayout.removeComponent(mandatoryLabel);
}
}
private void createCancelButton() {
cancelButton = SPUIComponentProvider.getButton(UIComponentIdProvider.CANCEL_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), "", "", true, VaadinIcons.CLOSE,
SPUIButtonStyleNoBorderWithIcon.class);
cancelButton.setSizeUndefined();
cancelButton.addStyleName("default-color");
addCloseListenerForCancelButton();
if (cancelButtonClickListener != null) {
cancelButton.addClickListener(cancelButtonClickListener);
}
buttonsLayout.addComponent(cancelButton);
buttonsLayout.setComponentAlignment(cancelButton, Alignment.MIDDLE_LEFT);
buttonsLayout.setExpandRatio(cancelButton, 1.0F);
}
private void createSaveButton() {
if (confirmStyle == ConfirmStyle.SAVE) {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.SAVE_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_SAVE), "", "", true, VaadinIcons.HARDDRIVE,
buttonDecorator);
} else if (confirmStyle == ConfirmStyle.NEXT) {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_NEXT), "", ValoTheme.BUTTON_PRIMARY, false, null,
buttonDecorator);
} else if (confirmStyle == ConfirmStyle.CONFIRM) {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_CONFIRM), "", ValoTheme.BUTTON_PRIMARY, false, null,
buttonDecorator);
} else {
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
i18n.getMessage(UIMessageIdProvider.BUTTON_OK), "", ValoTheme.BUTTON_PRIMARY, false, null,
buttonDecorator);
}
confirmButton.setSizeUndefined();
confirmButton.addStyleName("default-color");
addCloseListenerForSaveButton();
confirmButton.setEnabled(false);
confirmButton.setClickShortcut(KeyCode.ENTER);
buttonsLayout.addComponent(confirmButton);
buttonsLayout.setComponentAlignment(confirmButton, Alignment.MIDDLE_RIGHT);
buttonsLayout.setExpandRatio(confirmButton, 1.0F);
}
private void addHelpLink() {
if (StringUtils.isEmpty(helpLink)) {
return;
}
final Link helpLinkComponent = SPUIComponentProvider.getHelpLink(i18n, helpLink);
buttonsLayout.addComponent(helpLinkComponent);
buttonsLayout.setComponentAlignment(helpLinkComponent, Alignment.MIDDLE_RIGHT);
}
public AbstractComponent getButtonsLayout() {
return this.buttonsLayout;
}
public VerticalLayout getMainLayout() {
return mainLayout;
}
/**
* Enables the save confirmation button
*
* @param enabled
* boolean
*
*/
public void setSaveButtonEnabled(final boolean enabled) {
confirmButton.setEnabled(enabled);
}
public void setCancelButtonEnabled(final boolean enabled) {
cancelButton.setEnabled(enabled);
}
/**
* Sets the close listener in save dialog
*
* @param closeListener
* SaveDialogCloseListener
*/
public void setCloseListener(final SaveDialogCloseListener closeListener) {
this.closeListener = closeListener;
}
/**
* Check if the safe action can executed. After a the save action the
* listener checks if the dialog can closed.
*
*/
public interface SaveDialogCloseListener {
/**
* Checks if the safe action can executed.
*
* @return <true> = save action can executed <false> = cannot execute
* safe action .
*/
boolean canWindowSaveOrUpdate();
/**
* Checks if the window can be closed after the save action is executed
*
* @return <true> = window will close <false> = will not closed.
*/
default boolean canWindowClose() {
return true;
}
/**
* Saves/Updates action. Is called if canWindowSaveOrUpdate is <true>.
*
*/
void saveOrUpdate();
}
}

View File

@@ -1,98 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.vaadin.spring.events.EventBus.UIEventBus;
/**
* Container for commonly used dependencies in the UI.
*/
public class CommonUiDependencies {
private final VaadinMessageSource i18n;
private final EntityFactory entityFactory;
private final UIEventBus eventBus;
private final UINotification uiNotification;
private final SpPermissionChecker permChecker;
/**
* Public constructor.
*
* @param i18n
* VaadinMessageSource
* @param entityFactory
* EntityFactory
* @param eventBus
* UIEventBus
* @param uiNotification
* UINotification
* @param permChecker
* {@link SpPermissionChecker}
*/
public CommonUiDependencies(final VaadinMessageSource i18n, final EntityFactory entityFactory,
final UIEventBus eventBus, final UINotification uiNotification, final SpPermissionChecker permChecker) {
super();
this.i18n = i18n;
this.entityFactory = entityFactory;
this.eventBus = eventBus;
this.uiNotification = uiNotification;
this.permChecker = permChecker;
}
/**
* Returns {@link VaadinMessageSource}
*
* @return the i18n
*/
public VaadinMessageSource getI18n() {
return i18n;
}
/**
* Returns {@link EntityFactory}
*
* @return the entityFactory
*/
public EntityFactory getEntityFactory() {
return entityFactory;
}
/**
* Returns {@link UIEventBus}
*
* @return the eventBus
*/
public UIEventBus getEventBus() {
return eventBus;
}
/**
* Returns {@link UINotification}
*
* @return the uiNotification
*/
public UINotification getUiNotification() {
return uiNotification;
}
/**
* Returns {@link SpPermissionChecker}
*
* @return the permChecker
*/
public SpPermissionChecker getPermChecker() {
return permChecker;
}
}

View File

@@ -1,226 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.io.Serializable;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.vaadin.server.Resource;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
/**
* Class for the confirmation dialog which pops up when deleting, assigning...
* entities.
*/
public class ConfirmationDialog implements Serializable {
private static final long serialVersionUID = 1L;
private final transient Runnable callback;
private final CommonDialogWindow window;
public static Builder newBuilder(final VaadinMessageSource i18n, final String id) {
return new Builder(i18n, id);
}
/**
* Constructor for configuring confirmation dialog.
*
* @param i18n
* internationalization
* @param caption
* the dialog caption.
* @param question
* the question.
* @param hint
* added in the dialog
* @param onSaveOrUpdate
* the callback onSaveOrUpdate.
* @param onCancel
* the callback on cancel.
* @param icon
* the icon of the dialog
* @param id
* the id of the confirmation dialog
* @param tab
* ConfirmationTab which contains more information about the action
* which has to be confirmed, e.g. maintenance window
*/
private ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
final String hint, final Runnable onSaveOrUpdate, final Runnable onCancel, final Resource icon,
final String id, final Component tab) {
final VerticalLayout content = new VerticalLayout();
content.setMargin(false);
content.setSpacing(false);
if (question != null) {
content.addComponent(createConfirmationLabel(question));
}
if (hint != null) {
content.addComponent(createConfirmationLabel(hint));
}
if (tab != null) {
content.addComponent(tab);
}
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CONFIRMATION_WINDOW).caption(caption)
.content(content).cancelButtonClickListener(e -> {
if (onCancel != null) {
onCancel.run();
}
}).saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
.buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.OK).i18n(i18n);
if (!StringUtils.isEmpty(id)) {
windowBuilder.id(id);
}
this.window = windowBuilder.buildCommonDialogWindow();
window.setSaveButtonEnabled(true);
this.callback = onSaveOrUpdate;
if (icon != null) {
window.setIcon(icon);
}
window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_STYLE);
}
private SaveDialogCloseListener getSaveDialogCloseListener() {
return new SaveDialogCloseListener() {
@Override
public void saveOrUpdate() {
if (callback != null) {
callback.run();
}
}
@Override
public boolean canWindowSaveOrUpdate() {
return true;
}
};
}
private static Label createConfirmationLabel(final String text) {
// ContentMode.HTML is used instead of ContentMode.PREFORMATTED here due
// to no linebreaks if an entity name is very long
final String questionHtmlSave = HawkbitCommonUtil.sanitizeHtml(text);
final Label questionLbl = new Label(questionHtmlSave, ContentMode.HTML);
questionLbl.setWidth(100, Unit.PERCENTAGE);
questionLbl.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_QUESTION_LABEL);
return questionLbl;
}
/**
* Enables the ok save button
*
* @param enabled
* boolean
*/
public void setOkButtonEnabled(final boolean enabled) {
window.setSaveButtonEnabled(enabled);
}
/**
* @return confirmation window
*/
public Window getWindow() {
return window;
}
/**
* Builder for a confirmation dialog
*/
public static class Builder {
private final VaadinMessageSource i18n;
private final String id;
private String caption;
private String question;
private String hint;
private Resource icon;
private Component tab;
private Runnable callbackOnSaveOrUpdate;
private Runnable callbackOnCancel;
/**
* private constructor
*
* @param i18n
* required field
* @param id
* required field
*/
Builder(final VaadinMessageSource i18n, final String id) {
this.i18n = i18n;
this.id = id;
}
public Builder caption(final String caption) {
this.caption = caption;
return this;
}
public Builder question(final String question) {
this.question = question;
return this;
}
public Builder hint(final String hint) {
this.hint = hint;
return this;
}
public Builder icon(final Resource icon) {
this.icon = icon;
return this;
}
public Builder tab(final Component tab) {
this.tab = tab;
return this;
}
public Builder onSaveOrUpdate(final Runnable callback) {
this.callbackOnSaveOrUpdate = callback;
return this;
}
public Builder onCancel(final Runnable callback) {
this.callbackOnCancel = callback;
return this;
}
public ConfirmationDialog build() {
Assert.isTrue(StringUtils.hasText(caption), "Caption cannot be null.");
return new ConfirmationDialog(i18n, caption, question, hint, callbackOnSaveOrUpdate, callbackOnCancel, icon,
id, tab);
}
}
}

View File

@@ -1,58 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.ui.AbstractColorPicker.Coordinates2Color;
/**
* Converts 2d-coordinates to a Color.
*/
public class CoordinatesToColor implements Coordinates2Color {
private static final long serialVersionUID = 1L;
@Override
public Color calculate(final int x, final int y) {
return calculateHSVColor(x, y);
}
@Override
public int[] calculate(final Color color) {
final float[] hsv = color.getHSV();
final int x = (int) Math.round(hsv[0] * 220.0);
final int y = calculateYCoordinateOfColor(hsv);
return new int[] { x, y };
}
private static Color calculateHSVColor(final int x, final int y) {
final float h = (float) (x / 220.0);
float s = 1F;
float v = 1F;
if (y < 110) {
s = (float) (y / 110.0);
} else if (y > 110) {
v = (float) (1.0 - (y - 110.0) / 110.0);
}
return new Color(Color.HSVtoRGB(h, s, v));
}
private static int calculateYCoordinateOfColor(final float[] hsv) {
int y;
// lower half
/* Assuming hsv[] array value will have in the range of 0 to 1 */
if (hsv[1] < 1F) {
y = (int) Math.round(hsv[1] * 110.0);
} else {
y = (int) Math.round(110.0 - ((double) hsv[1] + (double) hsv[2]) * 110.0);
}
return y;
}
}

View File

@@ -1,40 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
/**
* Base function for a validator used in window controllers.
*/
public class EntityValidator {
private final CommonUiDependencies uiDependencies;
/**
* Constructor
*
* @param uiDependencies
* {@link CommonUiDependencies}
*/
protected EntityValidator(final CommonUiDependencies uiDependencies) {
this.uiDependencies = uiDependencies;
}
protected void displayValidationError(final String messageKey, final Object... args) {
uiDependencies.getUiNotification()
.displayValidationError(uiDependencies.getI18n().getMessage(messageKey, args));
}
protected VaadinMessageSource getI18n() {
return uiDependencies.getI18n();
}
}

View File

@@ -1,37 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.function.Consumer;
import com.vaadin.ui.ComponentContainer;
/**
* Interface for entity window layout
*
* @param <T>
* Generic type entity
*/
public interface EntityWindowLayout<T> {
ComponentContainer getRootComponent();
void setEntity(final T proxyEntity);
T getEntity();
/**
* Method to add validation listeners.
*
* @param validationCallback
* Validation callback event
*/
void addValidationListener(final Consumer<Boolean> validationCallback);
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.Map;
/**
* Interface for event aware event listeners
*
*/
public interface EventListenersAwareLayout {
/**
* Restore components state
*/
default void restoreState() {
}
/**
* Update components on view enter
*/
default void onViewEnter() {
}
/**
* Set components state based on url parameters
*
* @param stateParameters
* map of state url parameters
*/
default void handleStateParameters(final Map<String, String> stateParameters) {
}
/**
* Subscribe event listeners
*/
default void subscribeListeners() {
}
/**
* Unsubscribe event listeners
*/
default void unsubscribeListeners() {
}
}

View File

@@ -1,219 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
import java.util.Collections;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import com.vaadin.server.VaadinService;
/**
* A Utility class to user details e.g. username
*/
public final class UserDetailsFormatter {
private static final String TRIM_APPENDIX = "...";
private UserDetailsFormatter() {
}
/**
* Load user details by the user name and format the user name to max 100
* characters. See
* {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}.
*
* @param username
* the user name
* @return the formatted user name (max 100 characters) cannot be <null>
*/
public static String loadAndFormatUsername(final String username) {
return loadAndFormatUsername(username, 100);
}
/**
* Load user details by {@link BaseEntity#getCreatedBy()} and format the
* user name. Use {@link UserDetailsFormatter#loadAndFormatUsername(String)}
*
* @param baseEntity
* the entity
* @return the formatted 'created at user name' (max 100 characters) cannot
* be <null>
*/
public static String loadAndFormatCreatedBy(final BaseEntity baseEntity) {
if (baseEntity == null || baseEntity.getCreatedBy() == null) {
return "";
}
return loadAndFormatUsername(baseEntity.getCreatedBy());
}
/**
* Load user details by {@link BaseEntity#getLastModifiedBy()} and format
* the user name. Use
* {@link UserDetailsFormatter#loadAndFormatUsername(String)}
*
* @param baseEntity
* the entity
* @return the formatted 'last modified by user name' (max 100 characters)
* cannot be <null>
*/
public static String loadAndFormatLastModifiedBy(final BaseEntity baseEntity) {
if (baseEntity == null || baseEntity.getLastModifiedBy() == null) {
return "";
}
return loadAndFormatUsername(baseEntity.getLastModifiedBy());
}
/**
* Load user details by the current session information and format the user
* name to max 12 characters. @see
* {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}
*
* @return the formatted user name (max 12 characters) cannot be <null>
*/
public static String formatCurrentUsername() {
return loadAndFormatUsername(getCurrentUser().getUsername(), 5);
}
/**
* Load user details by the user name and format the user name. If the
* loaded {@link UserDetails} is not an instance of a {@link UserPrincipal},
* then just the {@link UserDetails#getUsername()} will return.
*
* If first and last name available, they will combined. Otherwise the
* {@link UserPrincipal#getLoginname()} will formatted. The formatted name
* is reduced to 100 characters.
*
* @param username
* the user name
* @param expectedNameLength
* the name size of each name part
* @return the formatted user name (max expectedNameLength characters)
* cannot be <null>
*/
public static String loadAndFormatUsername(final String username, final int expectedNameLength) {
final UserDetails userDetails = loadUserByUsername(username);
return formatUserName(expectedNameLength, userDetails);
}
private static String formatUserName(final int expectedNameLength, final UserDetails userDetails) {
if (!(userDetails instanceof UserPrincipal)) {
return userDetails.getUsername();
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
return trimAndFormatDetail(userPrincipal.getLoginname(), expectedNameLength);
}
/**
* Format the current tenant. The information is loaded by the current
* session information.
*
* @return the formatted user name (max 8 characters) can be <null>
*/
public static String formatCurrentTenant() {
final UserDetails userDetails = getCurrentUser();
if (!(userDetails instanceof UserPrincipal)) {
return null;
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
return trimAndFormatDetail(userPrincipal.getTenant(), 8);
}
/**
* Format the current tenant. The information is loaded by the current
* session information.
*
* @return the formatted user name (max 8 characters) can be <null>
*/
public static Optional<String> getCurrentTenant() {
final UserDetails userDetails = getCurrentUser();
if (!(userDetails instanceof UserPrincipal)) {
return Optional.empty();
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
return Optional.of(userPrincipal.getTenant().trim());
}
/**
* @return logged in users Email address
*/
public static Optional<String> getCurrentUserEmail() {
final UserDetails userDetails = getCurrentUser();
if (!(userDetails instanceof UserPrincipal)) {
return Optional.empty();
}
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
return Optional.ofNullable(userPrincipal.getEmail());
}
/**
* @return Details of currently logged-in user
*/
public static UserDetails getCurrentUser() {
final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession()
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
final Authentication authentication = context.getAuthentication();
if (authentication instanceof OAuth2AuthenticationToken) {
final OidcUser oidcUser = (OidcUser) authentication.getPrincipal();
final Object details = authentication.getDetails();
String tenant = "DEFAULT";
if (details instanceof TenantAwareAuthenticationDetails) {
tenant = ((TenantAwareAuthenticationDetails) details).getTenant();
}
return new UserPrincipal(oidcUser.getPreferredUsername(), "***", oidcUser.getGivenName(),
oidcUser.getFamilyName(), oidcUser.getPreferredUsername(), oidcUser.getEmail(), tenant,
oidcUser.getAuthorities());
} else {
return (UserDetails) authentication.getPrincipal();
}
}
private static String trimAndFormatDetail(final String formatString, final int expectedDetailLength) {
final String detail = StringUtils.defaultIfEmpty(formatString, "");
final String trimmedDetail = StringUtils.substring(detail, 0, expectedDetailLength);
if (StringUtils.length(detail) > expectedDetailLength) {
return trimmedDetail + TRIM_APPENDIX;
}
return trimmedDetail;
}
// Exception squid:S1166 - exception has to be hidden
@SuppressWarnings({ "squid:S1166" })
private static UserDetails loadUserByUsername(final String username) {
final UserDetailsService userDetailsService = SpringContextHolder.getInstance()
.getBean(UserDetailsService.class);
try {
return userDetailsService.loadUserByUsername(username);
} catch (final UsernameNotFoundException e) {
return new User(username, "", Collections.emptyList());
}
}
}

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2021 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common;
/**
* Interface for getting view name
*
*/
@FunctionalInterface
public interface ViewNameAware {
/**
* Provides the name of a view
*
* @return view name
*/
String getViewName();
}

View File

@@ -1,164 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import org.springframework.util.StringUtils;
import com.vaadin.ui.AbstractTextField;
/**
* Abstract Text field builder.
*
* @param <T>
* type of the builder
* @param <E>
* the text component
*
*/
public abstract class AbstractTextFieldBuilder<T, E extends AbstractTextField> {
private String caption;
private String style;
private String styleName;
private String prompt;
private String id;
private boolean readOnly;
private boolean enabled = true;
private final int maxLengthAllowed;
protected AbstractTextFieldBuilder(final int maxLengthAllowed) {
this.maxLengthAllowed = maxLengthAllowed;
}
/**
* Add caption to text field
*
* @param caption
* the caption to set
* @return the builder
*/
public T caption(final String caption) {
this.caption = caption;
this.prompt = caption;
return (T) this;
}
/**
* Add style to text field
*
* @param style
* the style to set * @return the builder
* @return the builder
*/
public T style(final String style) {
this.style = style;
return (T) this;
}
/**
* Add style name to text field
*
* @param styleName
* the styleName to set
* @return the builder
*/
public T styleName(final String styleName) {
this.styleName = styleName;
return (T) this;
}
/**
* Add read only to text field
*
* @param readOnly
* the readOnly to set
* @return the builder
*/
public T readOnly(final boolean readOnly) {
this.readOnly = readOnly;
return (T) this;
}
/**
* Enable the text field
*
* @param enabled
* the enabled to set
* @return the builder
*/
public T enabled(final boolean enabled) {
this.enabled = enabled;
return (T) this;
}
/**
* Add prompt to text field
*
* @param prompt
* the prompt to set
* @return the builder
*/
public T prompt(final String prompt) {
this.prompt = prompt;
return (T) this;
}
/**
* Add id to text field
*
* @param id
* the id to set
* @return the builder
*/
public T id(final String id) {
this.id = id;
return (T) this;
}
/**
* Build a textfield
*
* @return textfield
*/
public E buildTextComponent() {
final E textComponent = createTextComponent();
textComponent.setReadOnly(readOnly);
textComponent.setEnabled(enabled);
if (!StringUtils.isEmpty(caption)) {
textComponent.setCaption(caption);
}
if (!StringUtils.isEmpty(style)) {
textComponent.setStyleName(style);
}
if (!StringUtils.isEmpty(styleName)) {
textComponent.addStyleName(styleName);
}
if (!StringUtils.isEmpty(prompt)) {
textComponent.setPlaceholder(prompt);
}
if (maxLengthAllowed > 0) {
textComponent.setMaxLength(maxLengthAllowed);
}
if (!StringUtils.isEmpty(id)) {
textComponent.setId(id);
}
return textComponent;
}
protected abstract E createTextComponent();
}

View File

@@ -1,79 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import java.io.Serializable;
import com.vaadin.data.Binder.Binding;
import com.vaadin.ui.Component;
/**
* Holds a {@link Component} and its {@link Binding}
*
* @param <T>
* Component type
*/
public class BoundComponent<T extends Component> implements Serializable {
private static final long serialVersionUID = 1L;
private final T component;
private final Binding<?, ?> binding;
/**
* Constructor
*
* @param component
* component
* @param binding
* binding of the component
*/
public BoundComponent(final T component, final Binding<?, ?> binding) {
this.component = component;
this.binding = binding;
}
/**
* @return The component
*/
public T getComponent() {
return component;
}
/**
* Set to true if the component is required
*
* @param isRequired
* boolean
*/
public void setRequired(final boolean isRequired) {
binding.setAsRequiredEnabled(isRequired);
}
/**
* @return boolean
*/
public boolean isValid() {
return !binding.validate(false).isError();
}
/**
* Validate binding
*/
public void validate() {
binding.validate();
}
/**
* unbind the component
*/
public void unbind() {
binding.unbind();
}
}

View File

@@ -1,423 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
import org.eclipse.hawkbit.repository.model.Type;
import org.eclipse.hawkbit.ui.common.data.aware.ActionTypeAware;
import org.eclipse.hawkbit.ui.common.data.aware.DescriptionAware;
import org.eclipse.hawkbit.ui.common.data.aware.DsIdAware;
import org.eclipse.hawkbit.ui.common.data.aware.NameAware;
import org.eclipse.hawkbit.ui.common.data.aware.StartOptionAware;
import org.eclipse.hawkbit.ui.common.data.aware.TargetFilterQueryAware;
import org.eclipse.hawkbit.ui.common.data.aware.TypeInfoAware;
import org.eclipse.hawkbit.ui.common.data.aware.VersionAware;
import org.eclipse.hawkbit.ui.common.data.providers.AbstractProxyDataProvider;
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetStatelessDataProvider;
import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterQueryDataProvider;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.management.miscs.ActionTypeOptionGroupAssignmentLayout;
import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.TrimmingStringConverter;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.StringUtils;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.Binder.BindingBuilder;
import com.vaadin.data.Validator;
import com.vaadin.data.ValueProvider;
import com.vaadin.server.Setter;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
/**
* Builder class for from components
*/
public final class FormComponentBuilder {
public static final String TEXTFIELD_NAME = "textfield.name";
public static final String TEXTFIELD_VERSION = "textfield.version";
public static final String TEXTFIELD_DESCRIPTION = "textfield.description";
public static final String PROMPT_DISTRIBUTION_SET = "prompt.distribution.set";
public static final String PROMPT_TARGET_FILTER = "prompt.target.filter";
public static final String CAPTION_TYPE = "caption.type";
private FormComponentBuilder() {
}
/**
* Create an input field for a name
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the field
* @param i18n
* message source
* @param fieldId
* id of the field
* @return the TextField with its Binding
*/
public static <T extends NameAware> BoundComponent<TextField> createNameInput(final Binder<T> binder,
final VaadinMessageSource i18n, final String fieldId) {
final TextField nameInput = new TextFieldBuilder(NamedEntity.NAME_MAX_SIZE).id(fieldId)
.caption(i18n.getMessage(TEXTFIELD_NAME)).prompt(i18n.getMessage(TEXTFIELD_NAME)).buildTextComponent();
nameInput.setSizeUndefined();
final Binding<T, String> binding = binder.forField(nameInput).withConverter(new TrimmingStringConverter())
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_NAMEREQUIRED))
.bind(NameAware::getName, NameAware::setName);
return new BoundComponent<>(nameInput, binding);
}
/**
* Create a required input field for a version
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the field
* @param i18n
* message source
* @param fieldId
* id of the field
* @return the TextField
*/
public static <T extends VersionAware> BoundComponent<TextField> createVersionInput(final Binder<T> binder,
final VaadinMessageSource i18n, final String fieldId) {
final TextField versionInput = new TextFieldBuilder(NamedVersionedEntity.VERSION_MAX_SIZE).id(fieldId)
.caption(i18n.getMessage(TEXTFIELD_VERSION)).prompt(i18n.getMessage(TEXTFIELD_VERSION))
.buildTextComponent();
versionInput.setSizeUndefined();
final Binding<T, String> binding = binder.forField(versionInput).withConverter(new TrimmingStringConverter())
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_VERSIONREQUIRED))
.bind(VersionAware::getVersion, VersionAware::setVersion);
return new BoundComponent<>(versionInput, binding);
}
/**
* Create an optional input field for a description
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the field
* @param i18n
* message source
* @param fieldId
* id of the field
* @return the TextArea
*/
public static <T extends DescriptionAware> BoundComponent<TextArea> createDescriptionInput(final Binder<T> binder,
final VaadinMessageSource i18n, final String fieldId) {
return createBigTextInput(binder, i18n, fieldId, TEXTFIELD_DESCRIPTION, TEXTFIELD_DESCRIPTION,
DescriptionAware::getDescription, DescriptionAware::setDescription);
}
public static <T> BoundComponent<TextArea> createBigTextInput(final Binder<T> binder,
final VaadinMessageSource i18n, final String fieldId, final String caption, final String prompt,
final ValueProvider<T, String> getter, final Setter<T, String> setter) {
final TextArea descriptionInput = new TextAreaBuilder(NamedEntity.DESCRIPTION_MAX_SIZE).id(fieldId)
.caption(i18n.getMessage(caption)).prompt(i18n.getMessage(prompt)).style("text-area-style")
.buildTextComponent();
descriptionInput.setSizeUndefined();
final Binding<T, String> binding = binder.forField(descriptionInput).bind(getter, setter);
return new BoundComponent<>(descriptionInput, binding);
}
/**
* Create a bound {@link ActionTypeOptionGroupAssignmentLayout}
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the layout
* @param i18n
* message source
* @param componentId
* id of the input layout
* @return a bound layout
*/
public static <T extends ActionTypeAware> BoundComponent<ActionTypeOptionGroupAssignmentLayout> createActionTypeOptionGroupLayout(
final Binder<T> binder, final VaadinMessageSource i18n, final String componentId) {
final ActionTypeOptionGroupAssignmentLayout actionTypeOptionGroupLayout = new ActionTypeOptionGroupAssignmentLayout(
i18n, componentId);
binder.forField(actionTypeOptionGroupLayout.getActionTypeOptionGroup()).bind(ActionTypeAware::getActionType,
ActionTypeAware::setActionType);
final Binding<T, Long> binding = binder.forField(actionTypeOptionGroupLayout.getForcedTimeDateField())
.asRequired(i18n.getMessage("message.forcedTime.cannotBeEmpty")).withConverter(localDateTime -> {
if (localDateTime == null) {
return null;
}
return SPDateTimeUtil.localDateTimeToEpochMilli(localDateTime);
}, forcedTime -> {
if (forcedTime == null) {
return null;
}
return SPDateTimeUtil.epochMilliToLocalDateTime(forcedTime);
}).bind(ActionTypeAware::getForcedTime, ActionTypeAware::setForcedTime);
return new BoundComponent<>(actionTypeOptionGroupLayout, binding);
}
/**
* Create a bound {@link AutoStartOptionGroupLayout}
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the layout
* @param i18n
* message source
* @param componentId
* id of the input layout
* @return a bound layout
*/
public static <T extends StartOptionAware> BoundComponent<AutoStartOptionGroupLayout> createAutoStartOptionGroupLayout(
final Binder<T> binder, final VaadinMessageSource i18n, final String componentId) {
final AutoStartOptionGroupLayout autoStartOptionGroup = new AutoStartOptionGroupLayout(i18n, componentId);
binder.forField(autoStartOptionGroup.getAutoStartOptionGroup()).bind(StartOptionAware::getStartOption,
StartOptionAware::setStartOption);
final Binding<T, Long> binding = binder.forField(autoStartOptionGroup.getStartAtDateField())
.asRequired(i18n.getMessage("message.scheduledTime.cannotBeEmpty")).withConverter(localDateTime -> {
if (localDateTime == null) {
return null;
}
return SPDateTimeUtil.localDateTimeToEpochMilli(localDateTime);
}, startAtTime -> {
if (startAtTime == null) {
return null;
}
return SPDateTimeUtil.epochMilliToLocalDateTime(startAtTime);
}).bind(StartOptionAware::getStartAt, StartOptionAware::setStartAt);
return new BoundComponent<>(autoStartOptionGroup, binding);
}
/**
* create a bound input for distribution sets
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the input
* @param dataProvider
* provides distribution sets
* @param i18n
* i18n
* @param componentId
* id of the input layout
* @return bound ComboBox of distribution sets
*/
public static <T extends DsIdAware> BoundComponent<ComboBox<ProxyDistributionSet>> createDistributionSetComboBox(
final Binder<T> binder, final DistributionSetStatelessDataProvider dataProvider,
final VaadinMessageSource i18n, final String componentId) {
final ComboBox<ProxyDistributionSet> dsComboBox = SPUIComponentProvider.getComboBox(componentId,
i18n.getMessage(UIMessageIdProvider.HEADER_DISTRIBUTION_SET), i18n.getMessage(PROMPT_DISTRIBUTION_SET),
i18n.getMessage(PROMPT_DISTRIBUTION_SET), false, ProxyDistributionSet::getNameVersion, dataProvider);
final Binding<T, ProxyDistributionSetInfo> binding = binder.forField(dsComboBox)
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_REQUIRED))
.withConverter(ds -> {
if (ds == null) {
return null;
}
return ds.getInfo();
}, dsInfo -> {
if (dsInfo == null) {
return null;
}
return ProxyDistributionSet.of(dsInfo);
}).bind(DsIdAware::getDistributionSetInfo, DsIdAware::setDistributionSetInfo);
return new BoundComponent<>(dsComboBox, binding);
}
/**
* create a bound input for target filter queries.
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the input
* @param validator
* Target filter query validator
* @param dataProvider
* provides target filter queries
* @param i18n
* i18n
* @param componentId
* id of the input layout
* @return bound ComboBox of target filter queries
*/
public static <T extends TargetFilterQueryAware> BoundComponent<ComboBox<ProxyTargetFilterQuery>> createTargetFilterQueryCombo(
final Binder<T> binder, final Validator<ProxyTargetFilterQuery> validator,
final TargetFilterQueryDataProvider dataProvider, final VaadinMessageSource i18n,
final String componentId) {
final ComboBox<ProxyTargetFilterQuery> tfqCombo = SPUIComponentProvider.getComboBox(componentId, null,
i18n.getMessage(PROMPT_TARGET_FILTER), i18n.getMessage(PROMPT_TARGET_FILTER), true,
ProxyTargetFilterQuery::getName, dataProvider);
final BindingBuilder<T, ProxyTargetFilterQuery> bindingBuilder = binder.forField(tfqCombo)
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_TFQ_REQUIRED));
if (validator != null) {
bindingBuilder.withValidator(validator);
}
final Binding<T, ProxyTargetFilterQueryInfo> binding = bindingBuilder.withConverter(tfq -> {
if (tfq == null) {
return null;
}
return tfq.getInfo();
}, tfqInfo -> {
if (tfqInfo == null) {
return null;
}
return ProxyTargetFilterQuery.of(tfqInfo);
}).bind(TargetFilterQueryAware::getTargetFilterQueryInfo, TargetFilterQueryAware::setTargetFilterQueryInfo);
return new BoundComponent<>(tfqCombo, binding);
}
/**
* create a bound input for sm/ds types.
*
* @param <T>
* type of the binder
* @param binder
* that is bound to the input
* @param dataProvider
* provides types
* @param i18n
* i18n
* @param componentId
* id of the input layout
* @return bound ComboBox of sm/ds types
*/
public static <T extends TypeInfoAware> BoundComponent<ComboBox<ProxyTypeInfo>> createTypeCombo(
final Binder<T> binder, final AbstractProxyDataProvider<ProxyTypeInfo, ?, String> dataProvider,
final VaadinMessageSource i18n, final String componentId, final boolean isRequired) {
final ComboBox<ProxyTypeInfo> typeCombo = SPUIComponentProvider.getComboBox(componentId,
i18n.getMessage(CAPTION_TYPE), i18n.getMessage(CAPTION_TYPE), i18n.getMessage(CAPTION_TYPE), !isRequired,
ProxyTypeInfo::getName, dataProvider.withConvertedFilter(filterString -> filterString.trim() + "%"));
final BindingBuilder<T, ProxyTypeInfo> bindingBuilder = binder.forField(typeCombo);
if (isRequired){
bindingBuilder.asRequired(i18n.getMessage("message.error.typeRequired"));
}
final Binding<T, ProxyTypeInfo> binding = bindingBuilder.bind(TypeInfoAware::getTypeInfo, TypeInfoAware::setTypeInfo);
return new BoundComponent<>(typeCombo, binding);
}
/**
* Create type key text field
*
* @param binder
* that is bound to the input
* @param i18n
* i18n
*
* @return text field
*/
public static TextField createTypeKeyField(final Binder<ProxyType> binder, final VaadinMessageSource i18n) {
final TextField typeKey = new TextFieldBuilder(Type.KEY_MAX_SIZE).id(UIComponentIdProvider.TYPE_POPUP_KEY)
.caption(i18n.getMessage("textfield.key")).prompt(i18n.getMessage("textfield.key"))
.buildTextComponent();
typeKey.setSizeUndefined();
binder.forField(typeKey).withConverter(new TrimmingStringConverter())
.asRequired(i18n.getMessage("message.type.key.empty")).bind(ProxyType::getKey, ProxyType::setKey);
return typeKey;
}
/**
* Generate a check box
*
* @param <T>
* entity type the check box can be bound to
* @param id
* id of the check box element
* @param binder
* the box is bound to
* @param getter
* getter for the binder
* @param setter
* setter for the binder
* @return the bound box
*/
public static <T> CheckBox createCheckBox(final String id, final Binder<T> binder,
final ValueProvider<T, Boolean> getter, final Setter<T, Boolean> setter) {
return createCheckBox(null, id, binder, getter, setter);
}
/**
* Generate a check box
*
* @param <T>
* entity type the check box can be bound to
* @param caption
* check box caption
* @param id
* id of the check box element
* @param binder
* the box is bound to
* @param getter
* getter for the binder
* @param setter
* setter for the binder
* @return the bound box
*/
public static <T> CheckBox createCheckBox(final String caption, final String id, final Binder<T> binder,
final ValueProvider<T, Boolean> getter, final Setter<T, Boolean> setter) {
final CheckBox checkBox;
if (StringUtils.isEmpty(caption)) {
checkBox = new CheckBox();
} else {
checkBox = new CheckBox(caption);
}
checkBox.setId(id);
binder.forField(checkBox).bind(getter, setter);
return checkBox;
}
}

View File

@@ -1,548 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
import org.eclipse.hawkbit.ui.utils.StringHtmlEncoder;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.cronutils.utils.StringUtils;
import com.vaadin.data.ValueProvider;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.server.Resource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.Column;
import com.vaadin.ui.StyleGenerator;
import com.vaadin.ui.UI;
import com.vaadin.ui.components.grid.HeaderRow;
import com.vaadin.ui.themes.ValoTheme;
/**
* Builder class for grid components
*/
public final class GridComponentBuilder {
public static final double DEFAULT_MIN_WIDTH = 100D;
public static final String CREATED_BY_ID = "createdBy";
public static final String CREATED_DATE_ID = "createdDate";
public static final String MODIFIED_BY_ID = "modifiedBy";
public static final String MODIFIED_DATE_ID = "modifiedDate";
public static final String CREATED_BY_PROPERTY_NAME = "createdBy";
public static final String CREATED_AT_PROPERTY_NAME = "createdAt";
public static final String LAST_MODIFIED_BY_PROPERTY_NAME = "lastModifiedBy";
public static final String LAST_MODIFIED_AT_PROPERTY_NAME = "lastModifiedAt";
public static final String VERSION_PROPERTY_NAME = "version";
public static final String NAME_PROPERTY_NAME = "name";
public static final String CONTROLLER_ID_PROPERTY_NAME = "controllerId";
private GridComponentBuilder() {
}
/**
* Create a {@link Button} with link optic
*
* @param idSuffix
* suffix to build the button ID
* @param idPrefix
* prefix to build the button ID
* @param caption
* button caption
* @param enabled
* is button enabled
* @param clickListener
* execute on button click (null for none)
* @return the button
*/
public static Button buildLink(final String idSuffix, final String idPrefix, final String caption,
final boolean enabled, final ClickListener clickListener) {
final Button link = new Button();
final String id = new StringBuilder(idPrefix).append('.').append(idSuffix).toString();
link.setCaption(caption);
link.setEnabled(enabled);
link.setId(id);
link.addStyleName("borderless");
link.addStyleName("small");
link.addStyleName("on-focus-no-border");
link.addStyleName("link");
if (clickListener != null) {
link.addClickListener(clickListener);
}
link.setVisible(!StringUtils.isEmpty(caption));
return link;
}
/**
* Create a {@link Button} with link optic
*
* @param entity
* to build the button ID
* @param idPrefix
* prefix to build the button ID
* @param caption
* button caption
* @param enabled
* is button enabled
* @param clickListener
* execute on button click (null for none)
* @return the button
*/
public static <E extends ProxyNamedEntity> Button buildLink(final E entity, final String idPrefix,
final String caption, final boolean enabled, final ClickListener clickListener) {
final String idSuffix = StringHtmlEncoder.encode(entity.getName());
return buildLink(idSuffix, idPrefix, caption, enabled, clickListener);
}
/**
* Add name column to grid. The column is set to sortable which implies a
* JPA field "name" that is used for sorting.
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param i18n
* message source for internationalization
* @param columnId
* column ID
* @return the created column
*/
public static <E extends ProxyNamedEntity> Column<E, String> addNameColumn(final Grid<E> grid,
final VaadinMessageSource i18n, final String columnId) {
final Column<E, String> nameColumn = addColumn(i18n, grid, E::getName, "header.name", columnId,
DEFAULT_MIN_WIDTH);
setColumnSortable(nameColumn, NAME_PROPERTY_NAME);
return nameColumn;
}
/**
* Add controllerId column to grid. The column is set to sortable which implies a
* JPA field "controllerId" that is used for sorting.
*
* @param grid
* to add the column to
* @param i18n
* message source for internationalization
* @param columnId
* column ID
* @return the created column
*/
public static Column<ProxyTarget, Button> addControllerIdColumn(final Grid<ProxyTarget> grid,
final VaadinMessageSource i18n, final String columnId) {
final Column<ProxyTarget, Button> column = addComponentColumn(grid,
t -> buildControllerIdLink(t, columnId)).setId(columnId)
.setCaption(i18n.getMessage("header.controllerId")).setHidable(false)
.setMinimumWidth(DEFAULT_MIN_WIDTH);
setColumnSortable(column, CONTROLLER_ID_PROPERTY_NAME);
return column;
}
private static Button buildControllerIdLink(final ProxyTarget target, final String linkIdPrefix) {
final String idSuffix = StringHtmlEncoder.encode(target.getControllerId());
return buildLink(idSuffix, linkIdPrefix, target.getControllerId(), true, clickEvent -> UI.getCurrent()
.getNavigator().navigateTo("deployment/target=" + target.getControllerId()));
}
/**
* Add description column to grid
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param i18n
* message source for internationalization
* @param columnId
* column ID
* @return the created column
*/
public static <E extends ProxyNamedEntity> Column<E, String> addDescriptionColumn(final Grid<E> grid,
final VaadinMessageSource i18n, final String columnId) {
return addColumn(i18n, grid, E::getDescription, "header.description", columnId, DEFAULT_MIN_WIDTH);
}
/**
* Add "created by", "created at", "modified by" and "modified at" column
*
* @param <E>
* entity type of the grid
* @param grid
* to add the columns to
* @param i18n
* message source for internationalization
* @return the created columns
*/
public static <E extends ProxyNamedEntity> List<Column<E, String>> addCreatedAndModifiedColumns(final Grid<E> grid,
final VaadinMessageSource i18n) {
final List<Column<E, String>> columns = new ArrayList<>();
final Column<E, String> createdByColumn = addColumn(i18n, grid, E::getCreatedBy, "header.createdBy",
CREATED_BY_ID, DEFAULT_MIN_WIDTH);
setColumnSortable(createdByColumn, CREATED_BY_PROPERTY_NAME);
columns.add(createdByColumn);
final Column<E, String> createdDate = addColumn(i18n, grid, E::getCreatedDate, "header.createdDate", CREATED_DATE_ID, DEFAULT_MIN_WIDTH);
setColumnSortable(createdDate, CREATED_AT_PROPERTY_NAME);
columns.add(createdDate);
final Column<E, String> modifiedBy = addColumn(i18n, grid, E::getLastModifiedBy, "header.modifiedBy", MODIFIED_BY_ID, DEFAULT_MIN_WIDTH);
setColumnSortable(modifiedBy, LAST_MODIFIED_BY_PROPERTY_NAME);
columns.add(modifiedBy);
final Column<E, String> modifiedDate = addColumn(i18n, grid, E::getModifiedDate, "header.modifiedDate", MODIFIED_DATE_ID, DEFAULT_MIN_WIDTH);
setColumnSortable(modifiedDate, LAST_MODIFIED_AT_PROPERTY_NAME);
columns.add(modifiedDate);
return columns;
}
/**
* Add version column to grid
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param i18n
* message source for internationalization
* @param valueProvider
* to get the version of the entity
* @param columnId
* column ID
* @return the created column
*/
public static <E> Column<E, String> addVersionColumn(final Grid<E> grid, final VaadinMessageSource i18n,
final ValueProvider<E, String> valueProvider, final String columnId) {
final Column<E, String> column = addColumn(i18n, grid, valueProvider, "header.version", columnId,
DEFAULT_MIN_WIDTH);
setColumnSortable(column, VERSION_PROPERTY_NAME);
return column;
}
private static <E, T> Column<E, T> addColumn(final VaadinMessageSource i18n, final Grid<E> grid,
final ValueProvider<E, T> valueProvider, final String caption, final String columnID,
final double minWidth) {
final Column<E, T> col = addColumn(grid, valueProvider).setCaption(i18n.getMessage(caption))
.setMinimumWidth(minWidth);
if (columnID != null) {
col.setId(columnID);
}
return col;
}
/**
* Add column to grid with the standard settings
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param valueProvider
* providing the content
* @return the created column
*/
public static <E, T> Column<E, T> addColumn(final Grid<E> grid, final ValueProvider<E, T> valueProvider) {
return addColumn(grid, valueProvider, null);
}
/**
* Add column to grid with the standard settings
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param valueProvider
* providing the content
* @param styleGenerator
* providing additional styles
* @return the created column
*/
public static <E, T> Column<E, T> addColumn(final Grid<E> grid, final ValueProvider<E, T> valueProvider,
final StyleGenerator<E> styleGenerator) {
final Column<E, T> column = grid.addColumn(valueProvider);
commonColumnConfiguration(column, styleGenerator);
return column;
}
/**
* Remove column based on it's id
*
* @param grid
* to add the column to
* @param columnId
* of the column
* @param <E>
* entity type of the grid
*/
public static <E> void removeColumn(final Grid<E> grid, final String columnId) {
grid.removeColumn(columnId);
}
/**
* Check if a column is present based on it's id
*
* @param grid
* to add the column to
* @param columnId
* of the column
* @param <E>
* entity type of the grid
* @return if the column is present
*/
public static <E> boolean isColumnPresent(final Grid<E> grid, final String columnId) {
return grid.getColumn(columnId) != null;
}
/**
* Add column to grid with the standard settings
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param componentProvider
* providing the content
* @return the created column
*/
public static <E, T extends Component> Column<E, T> addComponentColumn(final Grid<E> grid,
final ValueProvider<E, T> componentProvider) {
return addComponentColumn(grid, componentProvider, null);
}
/**
* Add column to grid with the standard settings
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param componentProvider
* providing the content
* @param styleGenerator
* providing additional styles
* @return the created column
*/
public static <E, T extends Component> Column<E, T> addComponentColumn(final Grid<E> grid,
final ValueProvider<E, T> componentProvider, final StyleGenerator<E> styleGenerator) {
final Column<E, T> column = grid.addComponentColumn(componentProvider);
commonColumnConfiguration(column, styleGenerator);
return column;
}
private static <E, T> Column<E, T> commonColumnConfiguration(final Column<E, T> column,
final StyleGenerator<E> styleGenerator) {
column.setMinimumWidthFromContent(false);
column.setExpandRatio(1);
column.setSortable(false);
if (styleGenerator != null) {
column.setStyleGenerator(styleGenerator);
}
return column;
}
/**
* Add delete button column to grid
*
* @param <E>
* entity type of the grid
* @param grid
* to add the column to
* @param i18n
* message source for internationalization
* @param columnId
* column ID
* @param deleteSupport
* that executes the deletion
* @param buttonIdPrefix
* prefix to create the button IDs
* @param buttonEnabled
* is the button enabled
* @return the created column
*/
public static <E extends ProxyIdentifiableEntity> Column<E, Button> addDeleteColumn(final Grid<E> grid,
final VaadinMessageSource i18n, final String columnId, final DeleteSupport<E> deleteSupport,
final String buttonIdPrefix, final Predicate<E> buttonEnabled) {
final ValueProvider<E, Button> getDelButton = entity -> buildActionButton(i18n,
clickEvent -> deleteSupport.openConfirmationWindowDeleteAction(entity), VaadinIcons.TRASH,
UIMessageIdProvider.TOOLTIP_DELETE, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
buttonIdPrefix + "." + entity.getId(), buttonEnabled.test(entity));
return addIconColumn(grid, getDelButton, columnId, i18n.getMessage("header.action.delete")).setWidth(60D)
.setHidingToggleCaption(i18n.getMessage("header.action.delete"));
}
/**
* Add an action button column to a grid
*
* @param <T>
* type of the entity displayed by the grid
* @param grid
* to add the column to
* @param iconProvider
* to get the icon from
* @param columnId
* column ID
* @param caption
* caption of the column
* @return the created column
*/
public static <T, V extends Component> Column<T, V> addIconColumn(final Grid<T> grid,
final ValueProvider<T, V> iconProvider, final String columnId, final String caption) {
return addIconColumn(grid, iconProvider, columnId, caption, null);
}
/**
* Add an action button column to a grid
*
* @param <T>
* type of the entity displayed by the grid
* @param grid
* to add the column to
* @param iconProvider
* to get the icon from
* @param columnId
* column ID
* @param caption
* caption of the column
* @param styleGenerator
* caption of the column
* @return the created column
*/
public static <T, V extends Component> Column<T, V> addIconColumn(final Grid<T> grid,
final ValueProvider<T, V> iconProvider, final String columnId, final String caption,
final StyleGenerator<T> styleGenerator) {
final StyleGenerator<T> additionalStyleGenerator = entity -> SPUIStyleDefinitions.ICON_CELL;
final StyleGenerator<T> finalStyleGenerator = merge(Arrays.asList(styleGenerator, additionalStyleGenerator));
final Column<T, V> column = grid.addComponentColumn(iconProvider).setId(columnId)
.setStyleGenerator(finalStyleGenerator).setWidth(60D).setResizable(false).setSortable(false);
if (!StringUtils.isEmpty(caption)) {
column.setCaption(caption);
}
return column;
}
/**
* Makes the column sortable.
*
* @param <T>
* type of the entity displayed by the grid
* @param <V>
* type of column value
* @param column
* the column to set sortable
* @param sortPropertyName
* the jpa property name to sort by
* @return the provided column
*/
public static <T, V> Column<T, V> setColumnSortable(final Column<T, V> column,
final String sortPropertyName) {
column.setSortable(true).setSortProperty(sortPropertyName);
return column;
}
private static <T> StyleGenerator<T> merge(final Collection<StyleGenerator<T>> generators) {
return item -> generators.stream().filter(Objects::nonNull).map(gen -> gen.apply(item)).filter(Objects::nonNull)
.collect(Collectors.joining(" "));
}
/**
* Join columns to form an action column
*
* @param i18n
* message source for internationalization
* @param headerRow
* header row
* @param columns
* columns to join
*/
public static void joinToActionColumn(final VaadinMessageSource i18n, final HeaderRow headerRow,
final List<Column<?, ?>> columns) {
joinToIconColumn(headerRow, i18n.getMessage("header.action"), columns);
}
/**
* Join columns to form an icon column
*
* @param headerRow
* header row
* @param headerCaption
* header caption
* @param columns
* columns to join
*/
public static void joinToIconColumn(final HeaderRow headerRow, final String headerCaption,
final List<Column<?, ?>> columns) {
columns.forEach(column -> {
column.setWidth(30D);
column.setResizable(false);
});
final Column<?, ?>[] columnArray = columns.toArray(new Column<?, ?>[columns.size()]);
headerRow.join(columnArray).setText(headerCaption);
}
/**
* Create an action button (e.g. a delete button)
*
* @param i18n
* message source for internationalization
* @param clickListener
* clickListener
* @param icon
* icon of the button
* @param descriptionMsgProperty
* displayed as tool tip
* @param style
* additional style
* @param buttonId
* ID of the button
* @param enabled
* is the button enabled
* @return the button
*/
public static Button buildActionButton(final VaadinMessageSource i18n, final ClickListener clickListener,
final Resource icon, final String descriptionMsgProperty, final String style, final String buttonId,
final boolean enabled) {
final Button actionButton = new Button();
actionButton.addClickListener(clickListener);
actionButton.setIcon(icon, i18n.getMessage(descriptionMsgProperty));
actionButton.setDescription(i18n.getMessage(descriptionMsgProperty));
actionButton.setEnabled(enabled);
actionButton.setId(buttonId);
actionButton.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED);
actionButton.addStyleName("button-no-border");
actionButton.addStyleName("action-type-padding");
actionButton.addStyleName(ValoTheme.BUTTON_ICON_ONLY);
actionButton.addStyleName(style);
return actionButton;
}
}

View File

@@ -1,120 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import org.springframework.util.StringUtils;
import com.vaadin.ui.Label;
import com.vaadin.ui.themes.ValoTheme;
/**
* Label Builder.
*
*/
public class LabelBuilder {
private String caption;
private String name;
private String id;
private boolean visible = true;
/**
* Add name to label
*
* @param name
* the value to set
* @return builder
*/
public LabelBuilder name(final String name) {
this.name = name;
return this;
}
/**
* Add caption to label
*
* @param caption
* the caption to set
* @return builder
*/
public LabelBuilder caption(final String caption) {
this.caption = caption;
return this;
}
/**
* Add id to label
*
* @param id
* the id to set
* @return builder
*/
public LabelBuilder id(final String id) {
this.id = id;
return this;
}
/**
* Toggle label visibility
*
* @param visible
* the visible to set
* @return builder
*/
public LabelBuilder visible(final boolean visible) {
this.visible = visible;
return this;
}
/**
* Build caption label.
*
* @return Label
*/
public Label buildCaptionLabel() {
final Label label = createLabel();
label.addStyleName("header-caption");
return label;
}
/**
* Build label.
*
* @return Label
*/
public Label buildLabel() {
final Label label = createLabel();
label.setWidth("-1px");
label.setHeight("-1px");
if (StringUtils.hasText(caption)) {
label.setCaption(caption);
}
return label;
}
private Label createLabel() {
final Label label = new Label(name);
label.setVisible(visible);
final StringBuilder style = new StringBuilder(ValoTheme.LABEL_SMALL);
style.append(' ');
style.append(ValoTheme.LABEL_BOLD);
label.addStyleName(style.toString());
if (id != null) {
label.setId(id);
}
return label;
}
}

View File

@@ -1,599 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import java.io.Serializable;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction.IsActiveDecoration;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress.ProgressSatus;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.rollout.ProxyFontIcon;
import org.eclipse.hawkbit.ui.rollout.RolloutManagementUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.util.StringUtils;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.server.FontIcon;
import com.vaadin.ui.Label;
/**
*
* Generate labels with icons according to entities' states
*
*/
public final class StatusIconBuilder {
private StatusIconBuilder() {
}
/**
* Generate labels with icons according to entities' {@link Status}
*
* @param <E>
* entity type
*/
public static class ActionStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<Status, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public ActionStatusIconSupplier(final VaadinMessageSource i18n, final Function<E, Status> getEntityStatus,
final String labelIdPrefix) {
super(i18n, Status.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_ACTION_STATUS_PREFIX + status.toString().toLowerCase());
addMapping(Status.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(Status.SCHEDULED, VaadinIcons.HOURGLASS_EMPTY, SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(Status.RUNNING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(Status.RETRIEVED, VaadinIcons.CHECK_CIRCLE_O, SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(Status.WARNING, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_ORANGE);
addMapping(Status.DOWNLOAD, VaadinIcons.CLOUD_DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(Status.DOWNLOADED, VaadinIcons.CLOUD_DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(Status.CANCELING, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(Status.CANCEL_REJECTED, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_ORANGE);
addMapping(Status.CANCELED, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(Status.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
addMapping(Status.WAIT_FOR_CONFIRMATION, VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_PENDING);
}
}
/**
* Generate labels with icons according to entities' {@link RolloutStatus}
*
* @param <E>
* entity type
*/
public static class RolloutStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<RolloutStatus, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public RolloutStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, RolloutStatus> getEntityStatus, final String labelIdPrefix) {
super(i18n, RolloutStatus.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_ROLLOUT_STATUS_PREFIX + status.toString().toLowerCase());
addMapping(RolloutStatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(RolloutStatus.PAUSED, VaadinIcons.PAUSE, SPUIStyleDefinitions.STATUS_ICON_BLUE);
addMapping(RolloutStatus.RUNNING, null, SPUIStyleDefinitions.STATUS_SPINNER_YELLOW);
addMapping(RolloutStatus.WAITING_FOR_APPROVAL, VaadinIcons.HOURGLASS,
SPUIStyleDefinitions.STATUS_ICON_ORANGE);
addMapping(RolloutStatus.APPROVAL_DENIED, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
addMapping(RolloutStatus.READY, VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
addMapping(RolloutStatus.STOPPED, VaadinIcons.STOP, SPUIStyleDefinitions.STATUS_ICON_RED);
addMapping(RolloutStatus.CREATING, null, SPUIStyleDefinitions.STATUS_SPINNER_GREY);
addMapping(RolloutStatus.STARTING, null, SPUIStyleDefinitions.STATUS_SPINNER_BLUE);
addMapping(RolloutStatus.DELETING, null, SPUIStyleDefinitions.STATUS_SPINNER_RED);
}
}
/**
* Generate labels with icons according to entities'
* {@link RolloutGroupStatus}
*
* @param <E>
* entity type
*/
public static class RolloutGroupStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<RolloutGroupStatus, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public RolloutGroupStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, RolloutGroupStatus> getEntityStatus, final String labelIdPrefix) {
super(i18n, RolloutGroupStatus.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_ROLLOUT_GROUP_STATUS_PREFIX
+ status.toString().toLowerCase());
addMapping(RolloutGroupStatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(RolloutGroupStatus.RUNNING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
addMapping(RolloutGroupStatus.READY, VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
addMapping(RolloutGroupStatus.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
addMapping(RolloutGroupStatus.SCHEDULED, VaadinIcons.HOURGLASS_START,
SPUIStyleDefinitions.STATUS_ICON_PENDING);
}
}
/**
* Generate labels with icons according to entities' {@link Status} and the
* current {@link RolloutGroup}
*
* @param <E>
* entity type
*/
public static class RolloutActionStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends ActionStatusIconSupplier<E> {
private static final long serialVersionUID = 1L;
private final transient RolloutGroupManagement rolloutGroupManagement;
private final RolloutManagementUIState rolloutManagementUIState;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
* @param rolloutGroupManagement
* management to get the current {@link RolloutGroup}
* @param rolloutManagementUIState
* UI state {@link RolloutGroup}
*/
public RolloutActionStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, Status> getEntityStatus, final String labelIdPrefix,
final RolloutGroupManagement rolloutGroupManagement,
final RolloutManagementUIState rolloutManagementUIState) {
super(i18n, getEntityStatus, labelIdPrefix);
this.rolloutGroupManagement = rolloutGroupManagement;
this.rolloutManagementUIState = rolloutManagementUIState;
}
@Override
public Label getLabel(final E entity) {
final Optional<RolloutGroup> group = rolloutGroupManagement
.get(rolloutManagementUIState.getSelectedRolloutGroupId());
final Optional<ProxyFontIcon> optionalIcon = getIcon(entity);
ProxyFontIcon icon;
if (optionalIcon.isPresent()) {
icon = getFontIconFromStatusMap(optionalIcon.get(), getEntityStatus.apply(entity), group.orElse(null));
} else {
icon = buildStatusIcon(group.orElse(null));
}
return getLabel(entity, icon);
}
private ProxyFontIcon getFontIconFromStatusMap(final ProxyFontIcon foundIcon, final Status status,
final RolloutGroup group) {
if (Status.DOWNLOADED == status && isDownloadOnly(group)) {
return getIconMap().get(Status.FINISHED);
}
return foundIcon;
}
private static boolean isDownloadOnly(final RolloutGroup group) {
if (group == null) {
return false;
}
return ActionType.DOWNLOAD_ONLY == group.getRollout().getActionType();
}
// Actions are not created for targets when rollout's status is
// READY and when duplicate assignment is done. In these cases
// display a appropriate status with description
private ProxyFontIcon buildStatusIcon(final RolloutGroup rolloutGroup) {
if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.READY) {
return new ProxyFontIcon(VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_ROLLOUT_GROUP_STATUS_PREFIX
+ RolloutGroupStatus.READY.toString().toLowerCase()));
} else if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.FINISHED) {
final DistributionSet dist = rolloutGroup.getRollout().getDistributionSet();
final String ds = HawkbitCommonUtil.getFormattedNameVersion(dist.getName(), dist.getVersion());
if (dist.isValid()) {
return new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_ASSIGNED, ds));
} else {
// invalidated ds, finished rollout but ds wasn't assigned
// to target
return new ProxyFontIcon(VaadinIcons.BAN, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_NOT_ASSIGNED, ds));
}
} else {
return generateUnknwonStateIcon();
}
}
}
/**
* Generate labels with icons according to entities'
* {@link IsActiveDecoration}
*
* @param <E>
* entity type
*/
public static class ActiveStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<IsActiveDecoration, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public ActiveStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, IsActiveDecoration> getEntityStatus, final String labelIdPrefix) {
super(i18n, IsActiveDecoration.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_ACTIVE_ACTION_STATUS_PREFIX + status.getMsgName());
addMapping(IsActiveDecoration.ACTIVE, null, SPUIStyleDefinitions.STATUS_ICON_ACTIVE);
addMapping(IsActiveDecoration.SCHEDULED, VaadinIcons.HOURGLASS_EMPTY,
SPUIStyleDefinitions.STATUS_ICON_PENDING);
addMapping(IsActiveDecoration.IN_ACTIVE, VaadinIcons.CHECK_CIRCLE,
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL);
addMapping(IsActiveDecoration.IN_ACTIVE_ERROR, VaadinIcons.CHECK_CIRCLE,
SPUIStyleDefinitions.STATUS_ICON_RED);
}
}
/**
* Generate labels with icons according to entities' {@link ActionType}
*
* @param <E>
* entity type
*/
public static class ActionTypeIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilder<ActionType, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public ActionTypeIconSupplier(final VaadinMessageSource i18n, final Function<E, ActionType> getEntityStatus,
final String labelIdPrefix) {
super(i18n, ActionType.class, getEntityStatus, labelIdPrefix);
addMapping(ActionType.FORCED, VaadinIcons.BOLT, SPUIStyleDefinitions.STATUS_ICON_FORCED,
UIMessageIdProvider.CAPTION_ACTION_FORCED);
addMapping(ActionType.TIMEFORCED, VaadinIcons.BOLT, SPUIStyleDefinitions.STATUS_ICON_FORCED,
UIMessageIdProvider.CAPTION_ACTION_FORCED);
addMapping(ActionType.SOFT, VaadinIcons.STEP_FORWARD, SPUIStyleDefinitions.STATUS_ICON_SOFT,
UIMessageIdProvider.CAPTION_ACTION_SOFT);
addMapping(ActionType.DOWNLOAD_ONLY, VaadinIcons.DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_DOWNLOAD_ONLY,
UIMessageIdProvider.CAPTION_ACTION_DOWNLOAD_ONLY);
}
}
/**
* Generate labels with confirmation icons according to entity' {@link ProxyTargetFilterQuery}
*/
public static class ConfirmationIconSupplier extends AbstractEntityStatusIconBuilder<ProxyTargetFilterQuery> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param labelIdPrefix
* to generate the label ID
*/
public ConfirmationIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
super(i18n, labelIdPrefix);
}
@Override
public Label getLabel(final ProxyTargetFilterQuery entity) {
final ProxyFontIcon icon;
if (entity.isAutoAssignmentEnabled() && entity.getDistributionSetInfo() != null) {
icon = entity.isConfirmationRequired()
? new ProxyFontIcon(VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_GREEN,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_REQUIRED))
: new ProxyFontIcon(VaadinIcons.USER_CHECK, SPUIStyleDefinitions.STATUS_ICON_RED,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_REQUIRED));
} else {
icon = new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE_O, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_CONFIGURED));
}
return getLabel(entity, icon);
}
}
/**
* Generate labels with icons according to entities'
* {@link TargetUpdateStatus}
*
* @param <E>
* entity type
*/
public static class TargetStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<TargetUpdateStatus, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public TargetStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, TargetUpdateStatus> getEntityStatus, final String labelIdPrefix) {
super(i18n, TargetUpdateStatus.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_TARGET_STATUS_PREFIX + status.toString().toLowerCase());
addMapping(TargetUpdateStatus.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
addMapping(TargetUpdateStatus.UNKNOWN, VaadinIcons.QUESTION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE);
addMapping(TargetUpdateStatus.IN_SYNC, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(TargetUpdateStatus.PENDING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
addMapping(TargetUpdateStatus.REGISTERED, VaadinIcons.DOT_CIRCLE,
SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
}
}
/**
* Generate labels with icons according to entities' {@link ProgressSatus}
*
* @param <E>
* entity type
*/
public static class ProgressStatusIconSupplier<E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilderWithGenetaredTooltip<ProgressSatus, E> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param getEntityStatus
* function to get the entitie's state
* @param labelIdPrefix
* to generate the label ID
*/
public ProgressStatusIconSupplier(final VaadinMessageSource i18n,
final Function<E, ProgressSatus> getEntityStatus, final String labelIdPrefix) {
super(i18n, ProgressSatus.class, getEntityStatus, labelIdPrefix,
status -> UIMessageIdProvider.TOOLTIP_UPLOAD_STATUS_PREFIX + status.toString().toLowerCase());
addMapping(ProgressSatus.INPROGRESS, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
addMapping(ProgressSatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
addMapping(ProgressSatus.FAILED, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
}
}
/**
* Generate labels with icons according to {@link ProxyTarget}s'
* PollStatusToolTip
*/
public static class TargetPollingStatusIconSupplier extends AbstractEntityStatusIconBuilder<ProxyTarget> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param labelIdPrefix
* to generate the label ID
*/
public TargetPollingStatusIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
super(i18n, labelIdPrefix);
}
@Override
public Label getLabel(final ProxyTarget entity) {
final String pollStatusToolTip = entity.getPollStatusToolTip();
final ProxyFontIcon icon = StringUtils.hasText(pollStatusToolTip)
? new ProxyFontIcon(VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
pollStatusToolTip)
: new ProxyFontIcon(VaadinIcons.CLOCK, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
i18n.getMessage(UIMessageIdProvider.TOOLTIP_IN_TIME));
return getLabel(entity, icon);
}
}
/**
* Generate labels with icons according to {@link ProxyAction}s' timeforced
* status and current time
*/
public static class TimeforcedIconSupplier extends AbstractEntityStatusIconBuilder<ProxyAction> {
private static final long serialVersionUID = 1L;
/**
* constructor
*
* @param i18n
* message source for internationalization
* @param labelIdPrefix
* to generate the label ID
*/
public TimeforcedIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
super(i18n, labelIdPrefix);
}
@Override
public Label getLabel(final ProxyAction action) {
if (ActionType.TIMEFORCED != action.getActionType()) {
return null;
}
final long currentTimeMillis = System.currentTimeMillis();
String style;
String description;
if (action.isHitAutoForceTime(currentTimeMillis)) {
style = SPUIStyleDefinitions.STATUS_ICON_GREEN;
final String duration = SPDateTimeUtil.getDurationFormattedString(action.getForcedTime(),
currentTimeMillis, i18n);
description = i18n.getMessage(UIMessageIdProvider.TOOLTIP_TIMEFORCED_FORCED_SINCE, duration);
} else {
style = SPUIStyleDefinitions.STATUS_ICON_PENDING;
final String duration = SPDateTimeUtil.getDurationFormattedString(currentTimeMillis,
action.getForcedTime(), i18n);
description = i18n.getMessage(UIMessageIdProvider.TOOLTIP_TIMEFORCED_FORCED_IN, duration);
}
final ProxyFontIcon icon = new ProxyFontIcon(VaadinIcons.TIMER, style, description);
return getLabel(action, icon);
}
}
private static class EntityStatusIconBuilderWithGenetaredTooltip<T extends Enum<T>, E extends ProxyIdentifiableEntity>
extends EntityStatusIconBuilder<T, E> {
private static final long serialVersionUID = 1L;
private final transient Function<T, String> tooltipGenerator;
protected EntityStatusIconBuilderWithGenetaredTooltip(final VaadinMessageSource i18n, final Class<T> statusType,
final Function<E, T> getEntityStatus, final String labelIdPrefix,
final Function<T, String> tooltipGenerator) {
super(i18n, statusType, getEntityStatus, labelIdPrefix);
this.tooltipGenerator = tooltipGenerator;
}
protected void addMapping(final T status, final FontIcon icon, final String style) {
addMapping(status, icon, style, tooltipGenerator.apply(status));
}
}
private static class EntityStatusIconBuilder<T extends Enum<T>, E extends ProxyIdentifiableEntity>
extends AbstractEntityStatusIconBuilder<E> {
private static final long serialVersionUID = 1L;
private final Map<T, ProxyFontIcon> iconMap;
protected final transient Function<E, T> getEntityStatus;
protected EntityStatusIconBuilder(final VaadinMessageSource i18n, final Class<T> statusType,
final Function<E, T> getEntityStatus, final String labelIdPrefix) {
super(i18n, labelIdPrefix);
this.iconMap = new EnumMap<>(statusType);
this.getEntityStatus = getEntityStatus;
}
protected void addMapping(final T status, final FontIcon icon, final String style, final String tooltip) {
iconMap.put(status, new ProxyFontIcon(icon, style, i18n.getMessage(tooltip)));
}
@Override
public Label getLabel(final E entity) {
final ProxyFontIcon icon = getIcon(entity).orElse(generateUnknwonStateIcon());
return getLabel(entity, icon);
}
protected Optional<ProxyFontIcon> getIcon(final E entity) {
final T status = getEntityStatus.apply(entity);
if (status != null) {
return Optional.ofNullable(iconMap.getOrDefault(status, null));
}
return Optional.empty();
}
protected Map<T, ProxyFontIcon> getIconMap() {
return iconMap;
}
}
private abstract static class AbstractEntityStatusIconBuilder<E extends ProxyIdentifiableEntity>
implements Serializable {
private static final long serialVersionUID = 1L;
protected final VaadinMessageSource i18n;
protected final String labelIdPrefix;
protected AbstractEntityStatusIconBuilder(final VaadinMessageSource i18n, final String labelIdPrefix) {
this.i18n = i18n;
this.labelIdPrefix = labelIdPrefix;
}
protected Label getLabel(final E entity, final ProxyFontIcon icon) {
final String entityStatusId = new StringBuilder(labelIdPrefix).append(".").append(entity.getId())
.toString();
return SPUIComponentProvider.getLabelIcon(icon, entityStatusId);
}
protected ProxyFontIcon generateUnknwonStateIcon() {
return new ProxyFontIcon(VaadinIcons.QUESTION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
i18n.getMessage(UIMessageIdProvider.LABEL_UNKNOWN));
}
/**
* Generate a label from the entity according to its state
*
* @param entity
* to read the state from
* @return the label
*/
public abstract Label getLabel(final E entity);
}
}

View File

@@ -1,43 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import com.vaadin.shared.ui.ValueChangeMode;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.themes.ValoTheme;
/**
* TextArea builder.
*
*/
public class TextAreaBuilder extends AbstractTextFieldBuilder<TextAreaBuilder, TextArea> {
private static final int INPUT_DEBOUNCE_TIMEOUT = 500;
/**
* Constructor.
*
* @param maxLengthAllowed
* for the text area
*/
public TextAreaBuilder(final int maxLengthAllowed) {
super(maxLengthAllowed);
}
@Override
protected TextArea createTextComponent() {
final TextArea textArea = new TextArea();
textArea.addStyleName(ValoTheme.TEXTAREA_SMALL);
textArea.setValueChangeMode(ValueChangeMode.LAZY);
textArea.setValueChangeTimeout(INPUT_DEBOUNCE_TIMEOUT);
return textArea;
}
}

View File

@@ -1,43 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import com.vaadin.shared.ui.ValueChangeMode;
import com.vaadin.ui.TextField;
import com.vaadin.ui.themes.ValoTheme;
/**
* Textfield builder.
*
*/
public class TextFieldBuilder extends AbstractTextFieldBuilder<TextFieldBuilder, TextField> {
private static final int INPUT_DEBOUNCE_TIMEOUT = 500;
/**
* Constructor.
*
* @param maxLengthAllowed
* as mandatory field
*/
public TextFieldBuilder(final int maxLengthAllowed) {
super(maxLengthAllowed);
}
@Override
protected TextField createTextComponent() {
final TextField textField = new TextField();
textField.addStyleName(ValoTheme.TEXTFIELD_SMALL);
textField.setValueChangeMode(ValueChangeMode.LAZY);
textField.setValueChangeTimeout(INPUT_DEBOUNCE_TIMEOUT);
return textField;
}
}

View File

@@ -1,223 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.builder;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Component;
import com.vaadin.ui.Window;
/**
* Builder for Window.
*/
public class WindowBuilder {
private String caption;
private Component content;
private ClickListener cancelButtonClickListener;
private String helpLink;
private VaadinMessageSource i18n;
private final String type;
private String id;
private boolean showMandatoryExplanation = true;
private ConfirmStyle confirmStyle = ConfirmStyle.SAVE;
private Class<? extends SPUIButtonDecorator> buttonDecorator = SPUIButtonStyleNoBorderWithIcon.class;
private SaveDialogCloseListener saveDialogCloseListener;
/**
* Constructor.
*
* @param type
* window type
*/
public WindowBuilder(final String type) {
this.type = type;
}
/**
* Set the SaveDialogCloseListener.
*
* @param saveDialogCloseListener
* the saveDialogCloseListener
* @return the window builder
*/
public WindowBuilder saveDialogCloseListener(final SaveDialogCloseListener saveDialogCloseListener) {
this.saveDialogCloseListener = saveDialogCloseListener;
return this;
}
/**
* Set the caption.
*
* @param caption
* the caption
* @return the window builder
*/
public WindowBuilder caption(final String caption) {
this.caption = caption;
return this;
}
/**
* Set the content.
*
* @param content
* the content
* @return the window builder
*/
public WindowBuilder content(final Component content) {
this.content = content;
return this;
}
/**
* Set the cancelButtonClickListener.
*
* @param cancelButtonClickListener
* the cancelButtonClickListener
* @return the window builder
*/
public WindowBuilder cancelButtonClickListener(final ClickListener cancelButtonClickListener) {
this.cancelButtonClickListener = cancelButtonClickListener;
return this;
}
/**
* Set the helpLink.
*
* @param helpLink
* the helpLink
* @return the window builder
*/
public WindowBuilder helpLink(final String helpLink) {
this.helpLink = helpLink;
return this;
}
/**
* Set the i18n.
*
* @param i18n
* the i18n
* @return the window builder
*/
public WindowBuilder i18n(final VaadinMessageSource i18n) {
this.i18n = i18n;
return this;
}
/**
* Set the id.
*
* @param id
* the id to set * @return the window builder
* @return the window builder
*/
public WindowBuilder id(final String id) {
this.id = id;
return this;
}
/**
* Hide the line that explains the mandatory decorator
*
* @return the window builder
*/
public WindowBuilder hideMandatoryExplanation() {
showMandatoryExplanation = false;
return this;
}
/**
* Set buttonDecorator.
*
* @param buttonDecorator
* the to style the confirm and cancel buttons
* @return the window builder
*/
public WindowBuilder buttonDecorator(final Class<? extends SPUIButtonDecorator> buttonDecorator) {
this.buttonDecorator = buttonDecorator;
return this;
}
/**
* Set buttonDecorator.
*
* @param confirmStyle
* what kind of button is used
* @return the window builder
*/
public WindowBuilder confirmStyle(final ConfirmStyle confirmStyle) {
this.confirmStyle = confirmStyle;
return this;
}
/**
* Build the common dialog window.
*
* @return the window.
*/
public CommonDialogWindow buildCommonDialogWindow() {
final CommonDialogWindow window = new CommonDialogWindow(caption, content, helpLink, saveDialogCloseListener,
cancelButtonClickListener, confirmStyle, buttonDecorator, i18n);
if (!showMandatoryExplanation) {
window.hideMandatoryExplanation();
}
decorateWindow(window);
return window;
}
private void decorateWindow(final Window window) {
if (id != null) {
window.setId(id);
}
if (SPUIDefinitions.CONFIRMATION_WINDOW.equals(type)) {
window.setDraggable(false);
window.setClosable(true);
window.addStyleName(SPUIStyleDefinitions.CONFIRMATION_WINDOW_CAPTION);
} else if (SPUIDefinitions.CREATE_UPDATE_WINDOW.equals(type)) {
window.setDraggable(true);
window.setClosable(true);
}
}
/**
* Build window based on type.
*
* @return Window
*/
public Window buildWindow() {
final Window window = new Window(caption);
window.setContent(content);
window.setSizeUndefined();
window.setModal(true);
window.setResizable(false);
decorateWindow(window);
if (SPUIDefinitions.CREATE_UPDATE_WINDOW.equals(type)) {
window.setClosable(false);
}
return window;
}
}

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
/**
* Element is used for action creation
*/
public interface ActionTypeAware {
void setActionType(ActionType actionType);
ActionType getActionType();
void setForcedTime(Long forcedTime);
Long getForcedTime();
}

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
/**
* Element is describable
*/
public interface DescriptionAware {
void setDescription(String name);
String getDescription();
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
/**
* Element provides a distribution set info
*/
public interface DsIdAware {
void setDistributionSetInfo(ProxyDistributionSetInfo dsInfo);
ProxyDistributionSetInfo getDistributionSetInfo();
}

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
/**
* Element is named
*/
public interface NameAware {
void setName(String name);
String getName();
}

View File

@@ -1,25 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout.AutoStartOption;
/**
* Element is used for rollout creation
*/
public interface StartOptionAware {
void setStartOption(AutoStartOption startOption);
AutoStartOption getStartOption();
void setStartAt(Long forcedTime);
Long getStartAt();
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
/**
* Element is used for target filter query combobox
*/
public interface TargetFilterQueryAware {
void setTargetFilterQueryInfo(ProxyTargetFilterQueryInfo tfqInfo);
ProxyTargetFilterQueryInfo getTargetFilterQueryInfo();
}

View File

@@ -1,21 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
/**
* Element provides type info.
*/
public interface TypeInfoAware {
void setTypeInfo(ProxyTypeInfo typeInfo);
ProxyTypeInfo getTypeInfo();
}

View File

@@ -1,19 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.aware;
/**
* Element is versioned
*/
public interface VersionAware {
void setVersion(String name);
String getVersion();
}

View File

@@ -1,97 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import java.util.Objects;
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetDistributionsStateDataProvider;
import com.google.common.base.MoreObjects;
/**
* Filter params for {@link DistributionSetDistributionsStateDataProvider}.
*/
public class DsDistributionsFilterParams extends DsFilterParams {
private static final long serialVersionUID = 1L;
private Long dsTypeId;
/**
* Constructor for DsDistributionsFilterParams
*/
public DsDistributionsFilterParams() {
this(null, null);
}
/**
* Constructor.
*
* @param searchText
* String
* @param dsTypeId
* Long
*/
public DsDistributionsFilterParams(final String searchText, final Long dsTypeId) {
super(searchText);
this.dsTypeId = dsTypeId;
}
/**
* Copy Constructor.
*
* @param filter
* A filter to be copied
*/
public DsDistributionsFilterParams(final DsDistributionsFilterParams filter) {
super(filter);
this.dsTypeId = filter.getDsTypeId();
}
/**
* @return DsTypeId
*/
public Long getDsTypeId() {
return dsTypeId;
}
/**
* Setter for DsTypeId
*
* @param dsTypeId
* Long
*/
public void setDsTypeId(final Long dsTypeId) {
this.dsTypeId = dsTypeId;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DsDistributionsFilterParams other = (DsDistributionsFilterParams) obj;
return Objects.equals(this.getSearchText(), other.getSearchText())
&& Objects.equals(this.getDsTypeId(), other.getDsTypeId());
}
@Override
public int hashCode() {
return Objects.hash(getSearchText(), getDsTypeId());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).add("dsTypeId", getDsTypeId())
.toString();
}
}

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetManagementStateDataProvider;
import com.google.common.base.MoreObjects;
import org.springframework.util.StringUtils;
/**
* Filter params for {@link DistributionSetManagementStateDataProvider}.
*/
public class DsFilterParams implements Serializable {
private static final long serialVersionUID = 1L;
private String searchText;
/**
* Constructor for DsManagementFilterParams
*/
public DsFilterParams() {
this("");
}
/**
* Constructor.
*
* @param searchText
* String as search text
*/
public DsFilterParams(final String searchText) {
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
}
/**
* Copy Constructor.
*
* @param filter
* A filter to be copied
*/
public DsFilterParams(final DsFilterParams filter) {
this.searchText = filter.getSearchText();
}
/**
* @return SearchText
*/
public String getSearchText() {
return searchText;
}
/**
* Setter for searchText
*
* @param searchText
* String
*/
public void setSearchText(final String searchText) {
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DsFilterParams other = (DsFilterParams) obj;
return Objects.equals(this.getSearchText(), other.getSearchText());
}
@Override
public int hashCode() {
return Objects.hash(getSearchText());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).toString();
}
}

View File

@@ -1,149 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetManagementStateDataProvider;
import com.google.common.base.MoreObjects;
/**
* Filter params for {@link DistributionSetManagementStateDataProvider}.
*/
public class DsManagementFilterParams extends DsFilterParams {
private static final long serialVersionUID = 1L;
private boolean noTagClicked;
private Collection<String> distributionSetTags;
private String pinnedTargetControllerId;
/**
* Constructor for DsManagementFilterParams
*/
public DsManagementFilterParams() {
this("", false, new ArrayList<>(), "");
}
/**
* Constructor.
*
* @param searchText
* String as search text
* @param noTagClicked
* boolean
* @param distributionSetTags
* List of String as distribution tags
* @param pinnedTargetControllerId
* String as pinned target controller Id
*/
public DsManagementFilterParams(final String searchText, final boolean noTagClicked,
final Collection<String> distributionSetTags, final String pinnedTargetControllerId) {
super(searchText);
this.noTagClicked = noTagClicked;
this.distributionSetTags = distributionSetTags;
this.pinnedTargetControllerId = pinnedTargetControllerId;
}
/**
* Copy Constructor.
*
* @param filter
* A filter to be copied
*/
public DsManagementFilterParams(final DsManagementFilterParams filter) {
super(filter);
this.noTagClicked = filter.isNoTagClicked();
this.distributionSetTags = filter.getDistributionSetTags() != null
? new ArrayList<>(filter.getDistributionSetTags())
: null;
this.pinnedTargetControllerId = filter.getPinnedTargetControllerId();
}
/**
* @return DistributionSetTags
*/
public Collection<String> getDistributionSetTags() {
return distributionSetTags;
}
/**
* Setter for distributionSetTags
*
* @param distributionSetTags
* collection of String
*/
public void setDistributionSetTags(final Collection<String> distributionSetTags) {
this.distributionSetTags = distributionSetTags;
}
/**
* @return PinnedTargetControllerId
*/
public String getPinnedTargetControllerId() {
return pinnedTargetControllerId;
}
/**
* Setter for pinnedTargetControllerId
*
* @param pinnedTargetControllerId
* String
*/
public void setPinnedTargetControllerId(final String pinnedTargetControllerId) {
this.pinnedTargetControllerId = pinnedTargetControllerId;
}
/**
* @return noTagClicked
*/
public boolean isNoTagClicked() {
return noTagClicked;
}
/**
* Setter for noTagClicked
*
* @param noTagClicked
* boolean
*/
public void setNoTagClicked(final boolean noTagClicked) {
this.noTagClicked = noTagClicked;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final DsManagementFilterParams other = (DsManagementFilterParams) obj;
return Objects.equals(this.getSearchText(), other.getSearchText())
&& Objects.equals(this.isNoTagClicked(), other.isNoTagClicked())
&& Objects.equals(this.getDistributionSetTags(), other.getDistributionSetTags())
&& Objects.equals(this.getPinnedTargetControllerId(), other.getPinnedTargetControllerId());
}
@Override
public int hashCode() {
return Objects.hash(getSearchText(), isNoTagClicked(), getDistributionSetTags(), getPinnedTargetControllerId());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).add("noTagClicked", isNoTagClicked())
.add("distributionSetTags", getDistributionSetTags())
.add("pinnedTargetControllerId", getPinnedTargetControllerId()).toString();
}
}

View File

@@ -1,148 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleDataProvider;
import com.google.common.base.MoreObjects;
import org.springframework.util.StringUtils;
/**
* Filter params for {@link SoftwareModuleDataProvider}.
*/
public class SwFilterParams implements Serializable {
private static final long serialVersionUID = 1L;
private String searchText;
private Long softwareModuleTypeId;
private Long lastSelectedDistributionId;
/**
* Constructor for SwFilterParams to initialize
*/
public SwFilterParams() {
this(null, null, null);
}
/**
* Constructor.
*
* @param searchText
* String as search text
* @param softwareModuleTypeId
* Long as software module Id
* @param lastSelectedDistributionId
* Long as Last selected Distribution Id
*/
public SwFilterParams(final String searchText, final Long softwareModuleTypeId,
final Long lastSelectedDistributionId) {
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
this.softwareModuleTypeId = softwareModuleTypeId;
this.lastSelectedDistributionId = lastSelectedDistributionId;
}
/**
* Copy Constructor.
*
* @param filter
* A filter to be copied
*/
public SwFilterParams(final SwFilterParams filter) {
this.searchText = filter.getSearchText();
this.softwareModuleTypeId = filter.getSoftwareModuleTypeId();
this.lastSelectedDistributionId = filter.getLastSelectedDistributionId();
}
/**
* Get SearchText
*
* @return searchText
*/
public String getSearchText() {
return searchText;
}
/**
* Setter for searchText
*
* @param searchText
* String
*/
public void setSearchText(final String searchText) {
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
}
/**
* Get softwareModuleTypeId
*
* @return softwareModuleTypeId
*/
public Long getSoftwareModuleTypeId() {
return softwareModuleTypeId;
}
/**
* Setter for softwareModuleTypeId
*
* @param softwareModuleTypeId
* Long
*/
public void setSoftwareModuleTypeId(final Long softwareModuleTypeId) {
this.softwareModuleTypeId = softwareModuleTypeId;
}
/**
* Get lastSelectedDistributionId
*
* @return lastSelectedDistributionId
*/
public Long getLastSelectedDistributionId() {
return lastSelectedDistributionId;
}
/**
* Setter for lastSelectedDistributionId
*
* @param lastSelectedDistributionId
* Long
*/
public void setLastSelectedDistributionId(final Long lastSelectedDistributionId) {
this.lastSelectedDistributionId = lastSelectedDistributionId;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SwFilterParams other = (SwFilterParams) obj;
return Objects.equals(this.getSearchText(), other.getSearchText())
&& Objects.equals(this.getSoftwareModuleTypeId(), other.getSoftwareModuleTypeId())
&& Objects.equals(this.getLastSelectedDistributionId(), other.getLastSelectedDistributionId());
}
@Override
public int hashCode() {
return Objects.hash(getSearchText(), getSoftwareModuleTypeId(), getLastSelectedDistributionId());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("searchText", getSearchText())
.add("softwareModuleTypeId", getSoftwareModuleTypeId())
.add("lastSelectedDistributionId", getLastSelectedDistributionId()).toString();
}
}

View File

@@ -1,369 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.filters;
import com.google.common.base.MoreObjects;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.ui.common.data.providers.TargetManagementStateDataProvider;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
/**
* Filter params for {@link TargetManagementStateDataProvider}.
*/
public class TargetManagementFilterParams implements Serializable {
private static final long serialVersionUID = 1L;
private Long pinnedDistId;
private String searchText;
private Collection<TargetUpdateStatus> targetUpdateStatusList;
private boolean overdueState;
private Long distributionId;
private boolean noTagClicked;
private Collection<String> targetTags;
private Long targetFilterQueryId;
private boolean noTargetTypeClicked;
private Long targetTypeId;
/**
* Constructor for TargetManagementFilterParams to initialize
*/
public TargetManagementFilterParams() {
this(null, null, Collections.emptyList(), false, null, false, Collections.emptyList(), null, false, null);
}
/**
* Constructor.
*
* @param pinnedDistId
* Id for Pinned distribution
* @param searchText
* String as search text
* @param targetUpdateStatusList
* Collection of TargetUpdateStatus
* @param overdueState
* boolean
* @param distributionId
* Long
* @param noTagClicked
* boolean
* @param targetTags
* Collection of string as target tags
* @param targetFilterQueryId
* Id for target filter query
*/
public TargetManagementFilterParams(final Long pinnedDistId, final String searchText,
final Collection<TargetUpdateStatus> targetUpdateStatusList, final boolean overdueState,
final Long distributionId, final boolean noTagClicked, final Collection<String> targetTags,
final Long targetFilterQueryId, final boolean noTargetTypeClicked, final Long targetTypeId) {
this.pinnedDistId = pinnedDistId;
this.searchText = searchText;
this.targetUpdateStatusList = targetUpdateStatusList;
this.overdueState = overdueState;
this.distributionId = distributionId;
this.noTagClicked = noTagClicked;
this.targetTags = targetTags;
this.targetFilterQueryId = targetFilterQueryId;
this.noTargetTypeClicked = noTargetTypeClicked;
this.targetTypeId = targetTypeId;
}
/**
* Copy Constructor.
*
* @param filter
* A filter to be copied
*/
public TargetManagementFilterParams(final TargetManagementFilterParams filter) {
this.pinnedDistId = filter.getPinnedDistId();
this.searchText = filter.getSearchText();
this.targetUpdateStatusList = filter.getTargetUpdateStatusList() != null
? new ArrayList<>(filter.getTargetUpdateStatusList())
: null;
this.overdueState = filter.isOverdueState();
this.distributionId = filter.getDistributionId();
this.noTagClicked = filter.isNoTagClicked();
this.targetTags = filter.getTargetTags() != null ? new ArrayList<>(filter.getTargetTags()) : null;
this.noTargetTypeClicked = filter.isNoTargetTypeClicked();
this.targetTypeId = filter.getTargetTypeId();
this.targetFilterQueryId = filter.getTargetFilterQueryId();
}
/**
* Gets the flag that indicates if the filter is selected
*
* @return boolean <code>true</code> if the filter is selected, otherwise
* <code>false</code>
*/
public boolean isAnyFilterSelected() {
return isAnyTagSelected() || isAnyStatusFilterSelected() || isSearchActive() || isAnyComplexFilterSelected();
}
private boolean isAnyTagSelected() {
return !CollectionUtils.isEmpty(targetTags) || noTagClicked;
}
private boolean isAnyStatusFilterSelected() {
return !CollectionUtils.isEmpty(targetUpdateStatusList) || overdueState;
}
private boolean isSearchActive() {
return !StringUtils.isEmpty(searchText);
}
private boolean isAnyComplexFilterSelected() {
return distributionId != null || targetFilterQueryId != null || isAnyTypeSelected();
}
private boolean isAnyTypeSelected(){
return targetTypeId != null || isNoTargetTypeClicked();
}
/**
* Gets the pinnedDistId
*
* @return Id for pinned distribution
*/
public Long getPinnedDistId() {
return pinnedDistId;
}
/**
* Sets the pinnedDistId
*
* @param pinnedDistId
* Id for pinned distribution
*/
public void setPinnedDistId(final Long pinnedDistId) {
this.pinnedDistId = pinnedDistId;
}
/**
* Gets the searchText
*
* @return searchText
*/
public String getSearchText() {
return searchText;
}
/**
* Sets the searchText
*
* @param searchText
* Text for search
*/
public void setSearchText(final String searchText) {
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
}
/**
* Gets the targetUpdateStatusList
*
* @return Collection of targetUpdateStatus
*/
public Collection<TargetUpdateStatus> getTargetUpdateStatusList() {
return targetUpdateStatusList;
}
/**
* Sets the targetUpdateStatusList
*
* @param targetUpdateStatusList
* Collection of targetUpdateStatus
*/
public void setTargetUpdateStatusList(final Collection<TargetUpdateStatus> targetUpdateStatusList) {
this.targetUpdateStatusList = targetUpdateStatusList;
}
/**
* Gets the distributionId
*
* @return distributionId
*/
public Long getDistributionId() {
return distributionId;
}
/**
* Sets the distributionId
*
* @param distributionId
* Distribution Id
*/
public void setDistributionId(final Long distributionId) {
this.distributionId = distributionId;
}
/**
* Gets the targetTags
*
* @return targetTags
*/
public Collection<String> getTargetTags() {
return targetTags;
}
/**
* Sets the targetTags
*
* @param targetTags
* Collection of targetTags
*/
public void setTargetTags(final Collection<String> targetTags) {
this.targetTags = targetTags;
}
/**
* Gets the targetFilterQueryId
*
* @return targetFilterQueryId Id for target filter query
*/
public Long getTargetFilterQueryId() {
return targetFilterQueryId;
}
/**
* Sets the targetFilterQueryId
*
* @param targetFilterQueryId
* Id for target filter query
*/
public void setTargetFilterQueryId(final Long targetFilterQueryId) {
this.targetFilterQueryId = targetFilterQueryId;
}
/**
* Gets the state of overdue
*
* @return overdueState <code>true</code> if the state is set, otherwise
* <code>false</code>
*/
public boolean isOverdueState() {
return overdueState;
}
/**
* Sets the state of overDue
*
* @param overdueState
* <code>true</code> if the state is set, otherwise
* <code>false</code>
*/
public void setOverdueState(final boolean overdueState) {
this.overdueState = overdueState;
}
/**
* Gets the status of tag clicked
*
* @return noTagClicked <code>true</code> if the tag is clicked, otherwise
* <code>false</code>
*/
public boolean isNoTagClicked() {
return noTagClicked;
}
/**
* Sets the state of overDue
*
* @param noTagClicked
* <code>true</code> if the tag is clicked, otherwise
* <code>false</code>
*/
public void setNoTagClicked(final boolean noTagClicked) {
this.noTagClicked = noTagClicked;
}
/**
* Gets the status of no target Type clicked
*
* @return noTargetTypeClicked <code>true</code> if it is clicked, otherwise
* <code>false</code>
*/
public boolean isNoTargetTypeClicked() {
return noTargetTypeClicked;
}
/**
* Sets the state of no target type filter
*
* @param noTargetTypeClicked
* <code>true</code> if the tag is clicked, otherwise
* <code>false</code>
*/
public void setNoTargetTypeClicked(boolean noTargetTypeClicked) {
this.noTargetTypeClicked = noTargetTypeClicked;
}
/**
* Gets the targetTypeId
*
* @return targetTypeId for target type filter
*/
public Long getTargetTypeId() {
return targetTypeId;
}
/**
* Sets the targetType
*
* @param targetTypeId
* Id of targetType
*/
public void setTargetTypeId(Long targetTypeId) {
this.targetTypeId = targetTypeId;
}
// equals requires all fields in condition
@SuppressWarnings("squid:S1067")
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TargetManagementFilterParams other = (TargetManagementFilterParams) obj;
return Objects.equals(this.getPinnedDistId(), other.getPinnedDistId())
&& Objects.equals(this.getSearchText(), other.getSearchText())
&& Objects.equals(this.getTargetUpdateStatusList(), other.getTargetUpdateStatusList())
&& Objects.equals(this.isOverdueState(), other.isOverdueState())
&& Objects.equals(this.getDistributionId(), other.getDistributionId())
&& Objects.equals(this.isNoTagClicked(), other.isNoTagClicked())
&& Objects.equals(this.getTargetTags(), other.getTargetTags())
&& Objects.equals(this.getTargetFilterQueryId(), other.getTargetFilterQueryId())
&& Objects.equals(this.isNoTargetTypeClicked(), other.isNoTargetTypeClicked())
&& Objects.equals(this.getTargetTypeId(), other.getTargetTypeId());
}
@Override
public int hashCode() {
return Objects.hash(getPinnedDistId(), getSearchText(), getTargetUpdateStatusList(), isOverdueState(),
getDistributionId(), isNoTagClicked(), getTargetTags(), getTargetFilterQueryId(), isNoTargetTypeClicked(), getTargetTypeId());
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("pinnedDistId", getPinnedDistId())
.add("searchText", getSearchText()).add("targetUpdateStatusList", getTargetUpdateStatusList())
.add("overdueState", isOverdueState()).add("distributionId", getDistributionId())
.add("noTagClicked", isNoTagClicked()).add("targetTags", getTargetTags())
.add("targetFilterQueryId", getTargetFilterQueryId())
.add("noTargetTypeClicked", isNoTargetTypeClicked()).add("targetTypeId", getTargetTypeId()).toString();
}
}

View File

@@ -1,38 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
/**
* Maps named entities, fetched from backend, to the proxy named entities.
*
* @param <T>
* Generic type of ProxyNamedEntity
* @param <U>
* Generic type of NamedEntity
*/
public abstract class AbstractNamedEntityToProxyNamedEntityMapper<T extends ProxyNamedEntity, U extends NamedEntity>
implements NamedEntityToProxyNamedEntityMapper<T, U> {
protected void mapNamedEntityAttributes(final U namedEntity, final T proxyNamedEntity) {
proxyNamedEntity.setId(namedEntity.getId());
proxyNamedEntity.setName(namedEntity.getName());
proxyNamedEntity.setDescription(namedEntity.getDescription());
proxyNamedEntity.setCreatedAt(namedEntity.getCreatedAt());
proxyNamedEntity.setCreatedDate(SPDateTimeUtil.getFormattedDate(namedEntity.getCreatedAt()));
proxyNamedEntity.setLastModifiedAt(namedEntity.getLastModifiedAt());
proxyNamedEntity.setModifiedDate(SPDateTimeUtil.getFormattedDate(namedEntity.getLastModifiedAt()));
proxyNamedEntity.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(namedEntity));
proxyNamedEntity.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(namedEntity));
}
}

View File

@@ -1,32 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyActionStatus;
/**
* Maps {@link ActionStatus} entities, fetched from backend, to the
* {@link ProxyActionStatus} entities.
*/
public class ActionStatusToProxyActionStatusMapper
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyActionStatus, ActionStatus> {
@Override
public ProxyActionStatus map(final ActionStatus actionStatus) {
final ProxyActionStatus proxyAS = new ProxyActionStatus();
proxyAS.setCreatedAt(actionStatus.getCreatedAt());
proxyAS.setStatus(actionStatus.getStatus());
proxyAS.setId(actionStatus.getId());
return proxyAS;
}
}

View File

@@ -1,72 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction.IsActiveDecoration;
/**
* Maps {@link Action} entities, fetched from backend, to the
* {@link ProxyAction} entities.
*/
public class ActionToProxyActionMapper
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyAction, Action> {
@Override
public ProxyAction map(final Action action) {
final ProxyAction proxyAction = new ProxyAction();
proxyAction.setId(action.getId());
final String dsNameVersion = action.getDistributionSet().getName() + ":"
+ action.getDistributionSet().getVersion();
proxyAction.setDsNameVersion(dsNameVersion);
proxyAction.setActionType(action.getActionType());
proxyAction.setActive(action.isActive());
proxyAction.setIsActiveDecoration(buildIsActiveDecoration(action));
proxyAction.setLastModifiedAt(action.getLastModifiedAt());
proxyAction.setRolloutName(action.getRollout() != null ? action.getRollout().getName() : "");
proxyAction.setStatus(action.getStatus());
proxyAction
.setMaintenanceWindow(action.hasMaintenanceSchedule() ? buildMaintenanceWindowDisplayText(action) : "");
proxyAction.setMaintenanceWindowStartTime(action.getMaintenanceWindowStartTime().orElse(null));
proxyAction.setForcedTime(action.getForcedTime());
return proxyAction;
}
/**
* Generates a virtual IsActiveDecoration for the presentation layer that is
* calculated from {@link Action#isActive()} and
* {@link Action#getActionStatus()}.
*
* @param action
* the action combined IsActiveDecoration is calculated from
* @return IsActiveDecoration combined decoration for the presentation
* layer.
*/
private static IsActiveDecoration buildIsActiveDecoration(final Action action) {
final Action.Status status = action.getStatus();
if (status == Action.Status.SCHEDULED) {
return IsActiveDecoration.SCHEDULED;
} else if (status == Action.Status.ERROR) {
return IsActiveDecoration.IN_ACTIVE_ERROR;
}
return action.isActive() ? IsActiveDecoration.ACTIVE : IsActiveDecoration.IN_ACTIVE;
}
private static String buildMaintenanceWindowDisplayText(final Action action) {
return action.getMaintenanceWindowSchedule() + "/" + action.getMaintenanceWindowDuration() + "/"
+ action.getMaintenanceWindowTimeZone();
}
}

View File

@@ -1,62 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAdvancedRolloutGroup;
/**
* Maps {@link ProxyAdvancedRolloutGroup} entities, fetched from advanced group
* rows, to the {@link RolloutGroupCreate} entities.
*/
public class AdvancedRolloutGroupDefinitionToCreateMapper {
private final EntityFactory entityFactory;
/**
* Constructor for AdvancedRolloutGroupDefinitionToCreateMapper
*
* @param entityFactory
* the entity factory
*/
public AdvancedRolloutGroupDefinitionToCreateMapper(final EntityFactory entityFactory) {
this.entityFactory = entityFactory;
}
/**
* Map rollout group
*
* @param advancedRolloutGroupDefinition
* ProxyAdvancedRolloutGroup
*
* @return ProxyAdvancedRolloutGroup
*/
public RolloutGroupCreate map(final ProxyAdvancedRolloutGroup advancedRolloutGroupDefinition) {
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder()
.successAction(RolloutGroupSuccessAction.NEXTGROUP, null)
.successCondition(RolloutGroupSuccessCondition.THRESHOLD,
advancedRolloutGroupDefinition.getTriggerThresholdPercentage())
.errorCondition(RolloutGroupErrorCondition.THRESHOLD,
advancedRolloutGroupDefinition.getErrorThresholdPercentage())
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
return entityFactory.rolloutGroup().create().name(advancedRolloutGroupDefinition.getGroupName())
.description(advancedRolloutGroupDefinition.getGroupName())
.targetFilterQuery(advancedRolloutGroupDefinition.getTargetFilterQuery())
.targetPercentage(advancedRolloutGroupDefinition.getTargetPercentage()).conditions(conditions)
.confirmationRequired(advancedRolloutGroupDefinition.isConfirmationRequired());
}
}

View File

@@ -1,37 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyArtifact;
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
/**
* Maps {@link Artifact} entities, fetched from backend, to the
* {@link ProxyArtifact} entities.
*/
public class ArtifactToProxyArtifactMapper
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyArtifact, Artifact> {
@Override
public ProxyArtifact map(final Artifact artifact) {
final ProxyArtifact proxyArtifact = new ProxyArtifact();
proxyArtifact.setId(artifact.getId());
proxyArtifact.setFilename(artifact.getFilename());
proxyArtifact.setMd5Hash(artifact.getMd5Hash());
proxyArtifact.setSha1Hash(artifact.getSha1Hash());
proxyArtifact.setSha256Hash(artifact.getSha256Hash());
proxyArtifact.setSize(artifact.getSize());
proxyArtifact.setModifiedDate(SPDateTimeUtil.getFormattedDate(artifact.getLastModifiedAt()));
return proxyArtifact;
}
}

View File

@@ -1,41 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
/**
* Maps {@link AssignedSoftwareModule} entities, fetched from backend, to the
* {@link ProxySoftwareModule} entities.
*/
public class AssignedSoftwareModuleToProxyMapper
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxySoftwareModule, AssignedSoftwareModule> {
private final SoftwareModuleToProxyMapper softwareModuleToProxyMapper;
/**
* Constructor for SoftwareModuleToProxyMapper
*
* @param softwareModuleToProxyMapper
* SoftwareModuleToProxyMapper
*/
public AssignedSoftwareModuleToProxyMapper(final SoftwareModuleToProxyMapper softwareModuleToProxyMapper) {
this.softwareModuleToProxyMapper = softwareModuleToProxyMapper;
}
@Override
public ProxySoftwareModule map(final AssignedSoftwareModule assignedSwModule) {
final ProxySoftwareModule proxyModule = softwareModuleToProxyMapper.map(assignedSwModule.getSoftwareModule());
proxyModule.setAssigned(assignedSwModule.isAssigned());
return proxyModule;
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* Maps {@link DistributionSet} entities, fetched from backend, to the
* {@link ProxyDistributionSet} entities.
*/
public class DistributionSetToProxyDistributionMapper
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyDistributionSet, DistributionSet> {
@Override
public ProxyDistributionSet map(final DistributionSet distributionSet) {
final ProxyDistributionSet proxyDistribution = new ProxyDistributionSet();
mapNamedEntityAttributes(distributionSet, proxyDistribution);
proxyDistribution.setVersion(distributionSet.getVersion());
proxyDistribution.setNameVersion(
HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
proxyDistribution.setIsComplete(distributionSet.isComplete());
proxyDistribution.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
proxyDistribution.setIsValid(distributionSet.isValid());
final DistributionSetType type = distributionSet.getType();
final ProxyTypeInfo typeInfo = new ProxyTypeInfo(type.getId(), type.getName(), type.getKey());
proxyDistribution.setTypeInfo(typeInfo);
return proxyDistribution;
}
}

View File

@@ -1,36 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
/**
* Interface for mapping identifiable entities, fetched from backend, to the
* proxy identifiable entities.
*
* @param <T>
* Generic type of ProxyIdentifiableEntity
* @param <U>
* Generic type of Identifiable
*/
@FunctionalInterface
public interface IdentifiableEntityToProxyIdentifiableEntityMapper<T extends ProxyIdentifiableEntity, U extends Identifiable<Long>> {
/**
* Maps the provided {@link Identifiable} loaded from the backend to a new
* instance of {@link ProxyIdentifiableEntity}.
*
* @param identifiableEntity
* the {@link Identifiable} to map
* @return a new instance of {@link ProxyIdentifiableEntity}
*/
T map(U identifiableEntity);
}

View File

@@ -1,37 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.NamedEntity;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
/**
* Interface for mapping named entities, fetched from backend, to the proxy
* named entities.
*
* @param <T>
* Generic type of ProxyNamedEntity
* @param <U>
* Generic type of NamedEntity
*/
public interface NamedEntityToProxyNamedEntityMapper<T extends ProxyNamedEntity, U extends NamedEntity>
extends IdentifiableEntityToProxyIdentifiableEntityMapper<T, U> {
/**
* Maps the provided {@link NamedEntity} loaded from the backend to a new
* instance of {@link ProxyNamedEntity}.
*
* @param namedEntity
* the {@link NamedEntity} to map
* @return a new instance of {@link ProxyNamedEntity}
*/
@Override
T map(U namedEntity);
}

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAdvancedRolloutGroup;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.util.StringUtils;
/**
* Maps {@link RolloutGroup} entities, fetched from backend, to the
* {@link ProxyAdvancedRolloutGroup} entities.
*/
public class RolloutGroupToAdvancedDefinitionMapper {
private final TargetFilterQueryManagement targetFilterQueryManagement;
/**
* Constructor for RolloutGroupToAdvancedDefinitionMapper
*
* @param targetFilterQueryManagement
* TargetFilterQueryManagement
*/
public RolloutGroupToAdvancedDefinitionMapper(final TargetFilterQueryManagement targetFilterQueryManagement) {
this.targetFilterQueryManagement = targetFilterQueryManagement;
}
/**
* Map advanced Rollout Group
*
* @param rolloutGroup
* RolloutGroup
*
* @return ProxyAdvancedRolloutGroup
*/
public ProxyAdvancedRolloutGroup map(final RolloutGroup rolloutGroup) {
final ProxyAdvancedRolloutGroup advancedGroupRow = new ProxyAdvancedRolloutGroup();
advancedGroupRow.setGroupName(rolloutGroup.getName());
advancedGroupRow.setTargetsCount((long) rolloutGroup.getTotalTargets());
final String groupTargetFilterQuery = rolloutGroup.getTargetFilterQuery();
if (!StringUtils.isEmpty(groupTargetFilterQuery)) {
advancedGroupRow.setTargetFilterQuery(groupTargetFilterQuery);
final Slice<TargetFilterQuery> filterQueries = targetFilterQueryManagement.findByQuery(PageRequest.of(0, 1),
groupTargetFilterQuery);
if (filterQueries.getNumberOfElements() == 1) {
final TargetFilterQuery tfq = filterQueries.getContent().get(0);
advancedGroupRow.setTargetFilterQueryInfo(
new ProxyTargetFilterQueryInfo(tfq.getId(), tfq.getName(), tfq.getQuery()));
}
}
advancedGroupRow.setTargetPercentage(rolloutGroup.getTargetPercentage());
advancedGroupRow.setTriggerThresholdPercentage(rolloutGroup.getSuccessConditionExp());
advancedGroupRow.setErrorThresholdPercentage(rolloutGroup.getErrorConditionExp());
advancedGroupRow.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
return advancedGroupRow;
}
/**
* Fetch rollout group data from the backend
*
* @param rolloutId
* Rollout id
* @param rolloutGroupManagement
* RolloutGroupManagement
* @param pageCount
* Total page count
*
* @return List of advance rollout group
*/
public List<ProxyAdvancedRolloutGroup> loadRolloutGroupsFromBackend(final Long rolloutId,
final RolloutGroupManagement rolloutGroupManagement, final int pageCount) {
return rolloutGroupManagement.findByRollout(PageRequest.of(0, pageCount), rolloutId).stream().map(this::map)
.collect(Collectors.toList());
}
}

View File

@@ -1,63 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRolloutGroup;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* Maps {@link RolloutGroup} entities, fetched from backend, to the
* {@link ProxyRolloutGroup} entities.
*/
public class RolloutGroupToProxyRolloutGroupMapper
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyRolloutGroup, RolloutGroup> {
@Override
public ProxyRolloutGroup map(final RolloutGroup rolloutGroup) {
final ProxyRolloutGroup proxyRolloutGroup = new ProxyRolloutGroup();
mapNamedEntityAttributes(rolloutGroup, proxyRolloutGroup);
proxyRolloutGroup.setStatus(rolloutGroup.getStatus());
proxyRolloutGroup.setErrorAction(rolloutGroup.getErrorAction());
proxyRolloutGroup.setErrorActionExp(rolloutGroup.getErrorActionExp());
proxyRolloutGroup.setErrorCondition(rolloutGroup.getErrorCondition());
proxyRolloutGroup.setErrorConditionExp(rolloutGroup.getErrorConditionExp());
proxyRolloutGroup.setSuccessCondition(rolloutGroup.getSuccessCondition());
proxyRolloutGroup.setSuccessConditionExp(rolloutGroup.getSuccessConditionExp());
proxyRolloutGroup.setFinishedPercentage(formatFinishedPercentage(rolloutGroup));
proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets()));
proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus());
proxyRolloutGroup.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
return proxyRolloutGroup;
}
private static String formatFinishedPercentage(final RolloutGroup rolloutGroup) {
float tmpFinishedPercentage = 0;
switch (rolloutGroup.getStatus()) {
case READY:
case SCHEDULED:
case ERROR:
tmpFinishedPercentage = 0.0F;
break;
case FINISHED:
tmpFinishedPercentage = 100.0F;
break;
case RUNNING:
tmpFinishedPercentage = rolloutGroup.getTotalTargetCountStatus().getFinishedPercent();
break;
default:
break;
}
return String.format(HawkbitCommonUtil.getCurrentLocale(), "%.1f", tmpFinishedPercentage);
}
}

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRollout;
/**
* Maps {@link Rollout} entities, fetched from backend, to the
* {@link ProxyRollout} entities.
*/
public class RolloutToProxyRolloutMapper extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyRollout, Rollout> {
@Override
public ProxyRollout map(final Rollout rollout) {
final ProxyRollout proxyRollout = new ProxyRollout();
mapNamedEntityAttributes(rollout, proxyRollout);
final DistributionSet ds = rollout.getDistributionSet();
proxyRollout.setDsInfo(new ProxyDistributionSetInfo(ds.getId(), ds.getName(), ds.getVersion(), ds.isValid()));
proxyRollout
.setNumberOfGroups(rollout.getRolloutGroupsCreated() > 0 ? rollout.getRolloutGroupsCreated() : null);
proxyRollout.setForcedTime(rollout.getForcedTime() > 0 ? rollout.getForcedTime() : null);
proxyRollout.setStatus(rollout.getStatus());
proxyRollout.setStatusTotalCountMap(rollout.getTotalTargetCountStatus().getStatusTotalCountMap());
proxyRollout.setTotalTargets(rollout.getTotalTargets());
proxyRollout.setApprovalDecidedBy(rollout.getApprovalDecidedBy());
proxyRollout.setApprovalRemark(rollout.getApprovalRemark());
proxyRollout.setActionType(rollout.getActionType());
proxyRollout.setTargetFilterQuery(rollout.getTargetFilterQuery());
proxyRollout.setStartAt(rollout.getStartAt());
return proxyRollout;
}
}

View File

@@ -1,43 +0,0 @@
/**
* Copyright (c) 2020 Bosch.IO GmbH and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.ui.common.data.mappers;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
/**
* Maps {@link SoftwareModule} entities, fetched from backend, to the
* {@link ProxySoftwareModule} entities.
*/
public class SoftwareModuleToProxyMapper
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxySoftwareModule, SoftwareModule> {
@Override
public ProxySoftwareModule map(final SoftwareModule softwareModule) {
final ProxySoftwareModule proxySoftwareModule = new ProxySoftwareModule();
mapNamedEntityAttributes(softwareModule, proxySoftwareModule);
proxySoftwareModule.setVersion(softwareModule.getVersion());
proxySoftwareModule.setNameAndVersion(
HawkbitCommonUtil.concatStrings(":", softwareModule.getName(), softwareModule.getVersion()));
proxySoftwareModule.setVendor(softwareModule.getVendor());
proxySoftwareModule.setEncrypted(softwareModule.isEncrypted());
final SoftwareModuleType type = softwareModule.getType();
final ProxyTypeInfo typeInfo = new ProxyTypeInfo(type.getId(), type.getName(), type.getKey());
proxySoftwareModule.setTypeInfo(typeInfo);
return proxySoftwareModule;
}
}

Some files were not shown because too many files have changed in this diff Show More