diff --git a/.circleci/config.yml b/.circleci/config.yml index 74282802d..9bfeede28 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,10 +15,16 @@ jobs: docker: - image: circleci/openjdk:8u181-jdk-stretch + auth: + username: $DOCKERHUB_USER + password: $DOCKERHUB_ACCESSTOKEN environment: _JAVA_OPTIONS: "-Xms512m -Xmx1024m" - image: rabbitmq:3-management + auth: + username: $DOCKERHUB_USER + password: $DOCKERHUB_ACCESSTOKEN environment: RABBITMQ_DEFAULT_VHOST: "/" diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java index 87884f17f..713328029 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java @@ -20,6 +20,7 @@ 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; @@ -81,6 +82,16 @@ public class MgmtUiAutoConfiguration { 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. diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventPublisherHolder.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventPublisherHolder.java index b5223ad7d..1ff3fc040 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventPublisherHolder.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/model/helper/EventPublisherHolder.java @@ -35,7 +35,7 @@ public final class EventPublisherHolder { } /** - * @return the cache manager holder singleton instance + * @return the event publisher holder singleton instance */ public static EventPublisherHolder getInstance() { return SINGLETON; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/NoCountPagingRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/NoCountPagingRepository.java index 40713e173..4f32fff02 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/NoCountPagingRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/NoCountPagingRepository.java @@ -23,6 +23,7 @@ import org.springframework.data.domain.Slice; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; +import org.springframework.lang.Nullable; import org.springframework.stereotype.Repository; /** @@ -102,11 +103,12 @@ public class NoCountPagingRepository { } @Override - protected Page readPage(final TypedQuery query, final Pageable pageable, final Specification spec) { + protected Page readPage(final TypedQuery query, final Class domainClass, + final Pageable pageable, @Nullable final Specification spec) { query.setFirstResult((int) pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); - final List content = query.getResultList(); + final List content = query.getResultList(); return new PageImpl<>(content, pageable, content.size()); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index 96b028519..c7121f9ff 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -78,6 +78,7 @@ import org.slf4j.LoggerFactory; @Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"), @Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"), @Index(name = "sp_idx_target_04", columnList = "tenant,created_at"), + @Index(name = "sp_idx_target_05", columnList = "tenant,last_modified_at"), @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { "controller_id", "tenant" }, name = "uk_tenant_controller_id")) // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/DB2/V1_12_17__add_index_target_modified___DB2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/DB2/V1_12_17__add_index_target_modified___DB2.sql new file mode 100644 index 000000000..ac70ee7f0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/DB2/V1_12_17__add_index_target_modified___DB2.sql @@ -0,0 +1 @@ +CREATE INDEX sp_idx_target_05 ON sp_target (tenant, last_modified_at); \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_12_17__add_index_target_modified___H2.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_12_17__add_index_target_modified___H2.sql new file mode 100644 index 000000000..ac70ee7f0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/H2/V1_12_17__add_index_target_modified___H2.sql @@ -0,0 +1 @@ +CREATE INDEX sp_idx_target_05 ON sp_target (tenant, last_modified_at); \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_12_17__add_index_target_modified___MYSQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_12_17__add_index_target_modified___MYSQL.sql new file mode 100644 index 000000000..ac70ee7f0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/MYSQL/V1_12_17__add_index_target_modified___MYSQL.sql @@ -0,0 +1 @@ +CREATE INDEX sp_idx_target_05 ON sp_target (tenant, last_modified_at); \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/POSTGRESQL/V1_12_17__add_index_target_modified___POSTGRESQL.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/POSTGRESQL/V1_12_17__add_index_target_modified___POSTGRESQL.sql new file mode 100644 index 000000000..e509359e4 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/POSTGRESQL/V1_12_17__add_index_target_modified___POSTGRESQL.sql @@ -0,0 +1,3 @@ +CREATE INDEX sp_idx_target_05 +ON sp_target +USING BTREE (tenant, last_modified_at); \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/SQL_SERVER/V1_12_17__add_index_target_modified___SQL_SERVER.sql b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/SQL_SERVER/V1_12_17__add_index_target_modified___SQL_SERVER.sql new file mode 100644 index 000000000..ac70ee7f0 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/resources/db/migration/SQL_SERVER/V1_12_17__add_index_target_modified___SQL_SERVER.sql @@ -0,0 +1 @@ +CREATE INDEX sp_idx_target_05 ON sp_target (tenant, last_modified_at); \ No newline at end of file diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java index 92b0664a4..39f5efece 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java @@ -18,11 +18,12 @@ 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.SpringContextHelper; 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.vaadin.spring.events.EventBus.UIEventBus; import com.vaadin.annotations.Theme; @@ -100,6 +101,19 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener { 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 } } @@ -110,7 +124,6 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener { pushStrategy.init(getUI()); } addDetachListener(this); - SpringContextHelper.setContext(context); Responsive.makeResponsive(this); addStyleName(ValoTheme.UI_WITH_MENU); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java index b80748c27..dc7e2f0b9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java @@ -8,11 +8,13 @@ */ 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.ComponentContainer; +import com.vaadin.ui.VerticalLayout; /** * Class for sm metadata add/update window layout. @@ -24,23 +26,28 @@ public class SmMetaDataAddUpdateWindowLayout extends MetaDataAddUpdateWindowLayo * Constructor for AbstractTagWindowLayout * * @param i18n - * I18N + * VaadinMessageSource + * @param hasMetadataChangePermission + * checks the permission allowing to change metadata entities */ - public SmMetaDataAddUpdateWindowLayout(final VaadinMessageSource i18n) { - super(i18n); + public SmMetaDataAddUpdateWindowLayout(final VaadinMessageSource i18n, + final BooleanSupplier hasMetadataChangePermission) { + super(i18n, hasMetadataChangePermission); this.isVisibleForTarget = metaDataComponentBuilder.createVisibleForTargetsField(binder); } - /** - * @return form layout checkbox container for software module - */ @Override - public ComponentContainer getRootComponent() { - final ComponentContainer formLayout = super.getRootComponent(); + protected VerticalLayout getMetadataAddUpdateLayout() { + final VerticalLayout addUpdateLayout = super.getMetadataAddUpdateLayout(); + addUpdateLayout.addComponent(isVisibleForTarget); - formLayout.addComponent(isVisibleForTarget); + return addUpdateLayout; + } - return formLayout; + @Override + protected void disableMetadataInputComponents() { + super.disableMetadataInputComponents(); + isVisibleForTarget.setEnabled(false); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java index 2c6d9a8ca..e27939a84 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java @@ -67,9 +67,10 @@ public class SmMetaDataWindowLayout extends AbstractMetaDataWindowLayout { this.entityFactory = entityFactory; this.smMetaDataWindowGrid = new MetaDataWindowGrid<>(i18n, eventBus, permChecker, uiNotification, - new SmMetaDataDataProvider(smManagement), this::deleteMetaData); + new SmMetaDataDataProvider(smManagement), this::hasMetadataChangePermission, this::deleteMetaData); - this.smMetaDataAddUpdateWindowLayout = new SmMetaDataAddUpdateWindowLayout(i18n); + this.smMetaDataAddUpdateWindowLayout = new SmMetaDataAddUpdateWindowLayout(i18n, + this::hasMetadataChangePermission); this.addSmMetaDataWindowController = new AddMetaDataWindowController(i18n, uiNotification, smMetaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate); this.updateSmMetaDataWindowController = new UpdateMetaDataWindowController(i18n, uiNotification, diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java index e2cb74e89..a4334c7f5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java @@ -33,7 +33,7 @@ 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.SpringContextHelper; +import org.eclipse.hawkbit.ui.utils.SpringContextHolder; import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.slf4j.Logger; @@ -78,9 +78,9 @@ public abstract class AbstractFileTransferHandler implements Serializable { final Lock uploadLock) { this.artifactManagement = artifactManagement; this.i18n = i18n; - this.eventBus = SpringContextHelper.getBean(EventBus.UIEventBus.class); - this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class); - this.uiNotification = SpringContextHelper.getBean(UINotification.class); + this.eventBus = SpringContextHolder.getInstance().getBean(EventBus.UIEventBus.class); + this.artifactUploadState = SpringContextHolder.getInstance().getBean(ArtifactUploadState.class); + this.uiNotification = SpringContextHolder.getInstance().getBean(UINotification.class); this.uploadLock = uploadLock; } @@ -103,8 +103,9 @@ public abstract class AbstractFileTransferHandler implements Serializable { protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId, final String mimeType) { - SpringContextHelper.getBean("uiExecutor", Executor.class).execute(new TransferArtifactToRepositoryRunnable( - inputStream, fileUploadId, mimeType, UI.getCurrent(), uploadLock)); + SpringContextHolder.getInstance().getBean("uiExecutor", Executor.class) + .execute(new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent(), + uploadLock)); } private void interruptUploadAndSetReason(final String failureReason) { @@ -241,15 +242,15 @@ public abstract class AbstractFileTransferHandler implements Serializable { * Constructor for TransferArtifactToRepositoryRunnable * * @param inputStream - * InputStream + * InputStream * @param fileUploadId - * FileUploadId + * FileUploadId * @param mimeType - * String + * String * @param vaadinUi - * UI + * UI * @param uploadLock - * Lock + * Lock */ public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId, final String mimeType, final UI vaadinUi, final Lock uploadLock) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java index c67202f6a..4de3bb92a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java @@ -15,7 +15,7 @@ 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.SpringContextHelper; +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; @@ -179,10 +179,10 @@ public final class UserDetailsFormatter { public static UserDetails getCurrentUser() { final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession() .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); - Authentication authentication = context.getAuthentication(); + final Authentication authentication = context.getAuthentication(); if (authentication instanceof OAuth2AuthenticationToken) { - OidcUser oidcUser = (OidcUser) authentication.getPrincipal(); - Object details = authentication.getDetails(); + final OidcUser oidcUser = (OidcUser) authentication.getPrincipal(); + final Object details = authentication.getDetails(); String tenant = "DEFAULT"; if (details instanceof TenantAwareAuthenticationDetails) { tenant = ((TenantAwareAuthenticationDetails) details).getTenant(); @@ -207,7 +207,8 @@ public final class UserDetailsFormatter { // Exception squid:S1166 - exception has to be hidden @SuppressWarnings({ "squid:S1166" }) private static UserDetails loadUserByUsername(final String username) { - final UserDetailsService userDetailsService = SpringContextHelper.getBean(UserDetailsService.class); + final UserDetailsService userDetailsService = SpringContextHolder.getInstance() + .getBean(UserDetailsService.class); try { return userDetailsService.loadUserByUsername(username); } catch (final UsernameNotFoundException e) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowLayout.java index 208c4fd49..fe4d851bf 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowLayout.java @@ -38,6 +38,7 @@ public abstract class AbstractMetaDataWindowLayout extends HorizontalLayout { protected final VaadinMessageSource i18n; protected final transient UIEventBus eventBus; protected final UINotification uiNotification; + protected final SpPermissionChecker permChecker; private final MetadataWindowGridHeader metadataWindowGridHeader; @@ -62,9 +63,23 @@ public abstract class AbstractMetaDataWindowLayout extends HorizontalLayout { this.i18n = i18n; this.eventBus = eventBus; this.uiNotification = uiNotification; + this.permChecker = permChecker; this.metadataWindowGridHeader = new MetadataWindowGridHeader(i18n, permChecker, eventBus, - this::showAddMetaDataLayout); + this::hasMetadataChangePermission, this::showAddMetaDataLayout); + } + + // can be overriden in child classes for entity-specific permission + protected boolean hasMetadataChangePermission() { + return permChecker.hasUpdateRepositoryPermission(); + } + + private void showAddMetaDataLayout() { + getMetaDataWindowGrid().deselectAll(); + getAddMetaDataWindowController().populateWithData(null); + saveCallback.accept(getAddMetaDataWindowController().getSaveDialogCloseListener()); + + resetSaveButton(); } protected MetaData createMetaData(final ProxyMetaData entity) { @@ -129,14 +144,6 @@ public abstract class AbstractMetaDataWindowLayout extends HorizontalLayout { protected abstract void doDeleteMetaDataByKey(final String metaDataKey); - private void showAddMetaDataLayout() { - getMetaDataWindowGrid().deselectAll(); - getAddMetaDataWindowController().populateWithData(null); - saveCallback.accept(getAddMetaDataWindowController().getSaveDialogCloseListener()); - - resetSaveButton(); - } - /** * @return add meta data window controller */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetailsHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetailsHeader.java index 15c4c8d7e..69ab1ad50 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetailsHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetailsHeader.java @@ -34,17 +34,17 @@ public class DistributionSetDetailsHeader extends AbstractDetailsHeader { + private final BooleanSupplier hasMetadataChangePermission; protected final MetaDataAddUpdateWindowLayoutComponentBuilder metaDataComponentBuilder; private final TextField metadataKey; @@ -30,11 +33,15 @@ public class MetaDataAddUpdateWindowLayout extends AbstractEntityWindowLayout extends AbstractGrid implem public static final String META_DATA_VALUE_ID = "metaDataValue"; public static final String META_DATA_DELETE_BUTTON_ID = "metaDataDeleteButton"; + private final transient BooleanSupplier hasMetadataChangePermission; private final transient DeleteSupport metaDataDeleteSupport; /** @@ -52,17 +54,20 @@ public class MetaDataWindowGrid extends AbstractGrid implem * @param notification * UINotification * @param dataProvider - * AbstractMetaDataDataProvider for filter support + * provides entity-specific metadata entities + * @param hasMetadataChangePermission + * checks the permission allowing to change metadata entities * @param itemsDeletionCallback - * Grid item deletion Call back for event listener + * callback method to delete metadata entities * */ public MetaDataWindowGrid(final VaadinMessageSource i18n, final UIEventBus eventBus, final SpPermissionChecker permissionChecker, final UINotification notification, - final AbstractMetaDataDataProvider dataProvider, + final AbstractMetaDataDataProvider dataProvider, final BooleanSupplier hasMetadataChangePermission, final Predicate> itemsDeletionCallback) { super(i18n, eventBus, permissionChecker); + this.hasMetadataChangePermission = hasMetadataChangePermission; this.metaDataDeleteSupport = new DeleteSupport<>(this, i18n, notification, "caption.metadata", "caption.metadata.plur", ProxyMetaData::getKey, itemsDeletionCallback, UIComponentIdProvider.METADATA_DELETE_CONFIRMATION_DIALOG); @@ -79,7 +84,7 @@ public class MetaDataWindowGrid extends AbstractGrid implem @Override public String getGridId() { - return UIComponentIdProvider.METDATA_WINDOW_TABLE_ID; + return UIComponentIdProvider.METADATA_WINDOW_TABLE_ID; } @Override @@ -91,7 +96,7 @@ public class MetaDataWindowGrid extends AbstractGrid implem .setCaption(i18n.getMessage("header.value")).setHidden(true).setHidable(true); GridComponentBuilder.addDeleteColumn(this, i18n, META_DATA_DELETE_BUTTON_ID, metaDataDeleteSupport, - UIComponentIdProvider.META_DATA_DELET_ICON, e -> permissionChecker.hasDeleteRepositoryPermission()); + UIComponentIdProvider.META_DATA_DELET_ICON, e -> hasMetadataChangePermission.getAsBoolean()); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataDetailsGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataDetailsGrid.java index ddf1b4aa3..41eaa7385 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataDetailsGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataDetailsGrid.java @@ -83,7 +83,7 @@ public class MetadataDetailsGrid extends AbstractGrid imple @Override public String getGridId() { - return typePrefix + "." + UIComponentIdProvider.METDATA_DETAILS_TABLE_ID; + return typePrefix + "." + UIComponentIdProvider.METADATA_DETAILS_TABLE_ID; } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataWindowGridHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataWindowGridHeader.java index 761693acf..526a69724 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataWindowGridHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataWindowGridHeader.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.ui.common.detailslayout; +import java.util.function.BooleanSupplier; + import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.common.grid.header.AbstractGridHeader; import org.eclipse.hawkbit.ui.common.grid.header.support.AddHeaderSupport; @@ -35,15 +37,18 @@ public class MetadataWindowGridHeader extends AbstractGridHeader { * SpPermissionChecker * @param eventBus * UIEventBus + * @param hasMetadataChangePermission + * checks the permission allowing to change metadata entities * @param addNewItemCallback - * Runnable + * callback method to add new metadata entities */ public MetadataWindowGridHeader(final VaadinMessageSource i18n, final SpPermissionChecker permChecker, - final UIEventBus eventBus, final Runnable addNewItemCallback) { + final UIEventBus eventBus, final BooleanSupplier hasMetadataChangePermission, + final Runnable addNewItemCallback) { super(i18n, permChecker, eventBus); - if (permChecker.hasCreateRepositoryPermission()) { - this.addHeaderSupport = new AddHeaderSupport(i18n, UIComponentIdProvider.METADTA_ADD_ICON_ID, + if (hasMetadataChangePermission.getAsBoolean()) { + this.addHeaderSupport = new AddHeaderSupport(i18n, UIComponentIdProvider.METADATA_ADD_ICON_ID, addNewItemCallback, () -> false); } else { this.addHeaderSupport = null; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsHeader.java index 0e813ae2c..ea19ff039 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsHeader.java @@ -95,11 +95,6 @@ public class SoftwareModuleDetailsHeader extends AbstractDetailsHeader - * Generic type + * Generic type */ public abstract class AbstractDetailsHeader extends AbstractMasterAwareGridHeader { private static final long serialVersionUID = 1L; @@ -37,13 +37,13 @@ public abstract class AbstractDetailsHeader extends AbstractMasterAwareGridHe * Constructor for AbstractDetailsHeader * * @param i18n - * VaadinMessageSource + * VaadinMessageSource * @param permChecker - * SpPermissionChecker + * SpPermissionChecker * @param eventBus - * UIEventBus + * UIEventBus * @param uiNotification - * UINotification + * UINotification */ public AbstractDetailsHeader(final VaadinMessageSource i18n, final SpPermissionChecker permChecker, final UIEventBus eventBus, final UINotification uiNotification) { @@ -53,17 +53,29 @@ public abstract class AbstractDetailsHeader extends AbstractMasterAwareGridHe if (hasEditPermission()) { this.editDetailsHeaderSupport = new EditDetailsHeaderSupport(i18n, getEditIconId(), this::onEdit); + } else { + this.editDetailsHeaderSupport = null; + } + + if (hasMetadataReadPermission()) { this.metaDataDetailsHeaderSupport = new MetaDataDetailsHeaderSupport(i18n, getMetaDataIconId(), this::showMetaData); } else { - this.editDetailsHeaderSupport = null; this.metaDataDetailsHeaderSupport = null; } addHeaderSupports(Arrays.asList(editDetailsHeaderSupport, metaDataDetailsHeaderSupport)); } - protected abstract boolean hasEditPermission(); + // can be overriden in child classes for entity-specific permission + protected boolean hasEditPermission() { + return permChecker.hasUpdateRepositoryPermission(); + } + + // can be overriden in child classes for entity-specific permission + protected boolean hasMetadataReadPermission() { + return permChecker.hasReadRepositoryPermission(); + } protected abstract String getEditIconId(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/AddHeaderSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/AddHeaderSupport.java index 32ea1ff7b..390062f7a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/AddHeaderSupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/AddHeaderSupport.java @@ -35,13 +35,13 @@ public class AddHeaderSupport implements HeaderSupport { * Constructor for AddHeaderSupport * * @param i18n - * AddHeaderSupport + * VaadinMessageSource * @param addIconId - * Add icon id + * Add icon id * @param addItemCallback - * Runnable + * callback method to add new entities * @param maximizedStateSupplier - * BooleanSupplier + * provides the max/min state of the grid */ public AddHeaderSupport(final VaadinMessageSource i18n, final String addIconId, final Runnable addItemCallback, final BooleanSupplier maximizedStateSupplier) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 8a94bb486..e7c41f996 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -17,7 +17,7 @@ import javax.validation.ConstraintViolationException; import org.eclipse.hawkbit.ui.common.notification.ParallelNotification; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; -import org.eclipse.hawkbit.ui.utils.SpringContextHelper; +import org.eclipse.hawkbit.ui.utils.SpringContextHolder; import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.slf4j.Logger; @@ -106,7 +106,7 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { LOG.error("Error in UI: ", ex); final String errorMessage = extractMessageFrom(ex); - final VaadinMessageSource i18n = SpringContextHelper.getBean(VaadinMessageSource.class); + final VaadinMessageSource i18n = SpringContextHolder.getInstance().getBean(VaadinMessageSource.class); return buildErrorNotification(i18n.getMessage("caption.error"), errorMessage); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowLayout.java index a040e5bf3..3fb2868b3 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowLayout.java @@ -69,9 +69,9 @@ public class DsMetaDataWindowLayout extends AbstractMetaDataWindowLayout { this.entityFactory = entityFactory; this.dsMetaDataWindowGrid = new MetaDataWindowGrid<>(i18n, eventBus, permChecker, uiNotification, - new DsMetaDataDataProvider(dsManagement), this::deleteMetaData); + new DsMetaDataDataProvider(dsManagement), this::hasMetadataChangePermission, this::deleteMetaData); - this.metaDataAddUpdateWindowLayout = new MetaDataAddUpdateWindowLayout(i18n); + this.metaDataAddUpdateWindowLayout = new MetaDataAddUpdateWindowLayout(i18n, this::hasMetadataChangePermission); this.addDsMetaDataWindowController = new AddMetaDataWindowController(i18n, uiNotification, metaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate); this.updateDsMetaDataWindowController = new UpdateMetaDataWindowController(i18n, uiNotification, diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/AbstractHawkbitLoginUI.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/AbstractHawkbitLoginUI.java index 7d2f54cc5..0269aadaf 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/AbstractHawkbitLoginUI.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/login/AbstractHawkbitLoginUI.java @@ -21,7 +21,6 @@ import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.themes.HawkbitTheme; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; -import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; @@ -117,7 +116,6 @@ public abstract class AbstractHawkbitLoginUI extends UI { @Override protected void init(final VaadinRequest request) { HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n); - SpringContextHelper.setContext(context); params = UriComponentsBuilder.fromUri(Page.getCurrent().getLocation()).build().getQueryParams(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetDetails.java index c7ff9e213..142147fbf 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetDetails.java @@ -87,7 +87,7 @@ public class TargetDetails extends AbstractGridDetailsLayout { new SimpleEntry<>(i18n.getMessage("caption.tags.tab"), getTargetTagToken().getTagPanel()), new SimpleEntry<>(i18n.getMessage("caption.logs.tab"), logDetails))); - if (permissionChecker.hasCreateRepositoryPermission()) { + if (permissionChecker.hasReadRepositoryPermission()) { this.targetMetadataGrid = new MetadataDetailsGrid<>(i18n, eventBus, UIComponentIdProvider.TARGET_TYPE_PREFIX, this::showMetadataDetails, new TargetMetaDataDataProvider(targetManagement)); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowLayout.java index 20382efa8..012a7200c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowLayout.java @@ -70,9 +70,10 @@ public class TargetMetaDataWindowLayout extends AbstractMetaDataWindowLayout(i18n, eventBus, permChecker, uiNotification, - new TargetMetaDataDataProvider(targetManagement), this::deleteMetaData); + new TargetMetaDataDataProvider(targetManagement), this::hasMetadataChangePermission, + this::deleteMetaData); - this.metaDataAddUpdateWindowLayout = new MetaDataAddUpdateWindowLayout(i18n); + this.metaDataAddUpdateWindowLayout = new MetaDataAddUpdateWindowLayout(i18n, this::hasMetadataChangePermission); this.addTargetMetaDataWindowController = new AddMetaDataWindowController(i18n, uiNotification, metaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate); this.updateTargetMetaDataWindowController = new UpdateMetaDataWindowController(i18n, uiNotification, diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java index e272be40c..aa2ea94ba 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DelayedEventBusPushStrategy.java @@ -131,6 +131,9 @@ public class DelayedEventBusPushStrategy LOG.debug("Cleanup delayed event push strategy for UI {}", vaadinUI.getUIId()); jobHandle.cancel(true); queue.clear(); + + jobHandle = null; + vaadinUI = null; } private final class DispatchRunnable implements Runnable { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHelper.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHolder.java similarity index 72% rename from hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHelper.java rename to hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHolder.java index d268f8aca..da23f951c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHelper.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SpringContextHolder.java @@ -8,27 +8,31 @@ */ package org.eclipse.hawkbit.ui.utils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; /** * Singleton for the spring application context. - * - * - * */ -public final class SpringContextHelper { +public final class SpringContextHolder { - private static ApplicationContext context; + private static final SpringContextHolder SINGLETON = new SpringContextHolder(); + + @Autowired + private ApplicationContext context; /** * Private Constructor. */ - private SpringContextHelper() { + private SpringContextHolder() { // Utility class } - public static void setContext(final ApplicationContext context) { - SpringContextHelper.context = context; + /** + * @return the spring context holder singleton instance + */ + public static SpringContextHolder getInstance() { + return SINGLETON; } /** @@ -39,7 +43,7 @@ public final class SpringContextHelper { * application context * @return the requested bean */ - public static Object getBean(final String beanName) { + public Object getBean(final String beanName) { return context.getBean(beanName); } @@ -51,7 +55,7 @@ public final class SpringContextHelper { * application context * @return the requested bean */ - public static T getBean(final Class beanClazz) { + public T getBean(final Class beanClazz) { return context.getBean(beanClazz); } @@ -66,8 +70,7 @@ public final class SpringContextHelper { * application context * @return the requested bean */ - public static T getBean(final String beanName, final Class beanClazz) { + public T getBean(final String beanName, final Class beanClazz) { return context.getBean(beanName, beanClazz); } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java index e4e3c1701..f473c9dec 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java @@ -1244,15 +1244,15 @@ public final class UIComponentIdProvider { /** * Metadata add icon id. */ - public static final String METADTA_ADD_ICON_ID = "metadata.add.icon.id"; + public static final String METADATA_ADD_ICON_ID = "metadata.add.icon.id"; /** * Metadata details table id. */ - public static final String METDATA_DETAILS_TABLE_ID = "metadata.details.table.id"; + public static final String METADATA_DETAILS_TABLE_ID = "metadata.details.table.id"; /** * Metadata window table id. */ - public static final String METDATA_WINDOW_TABLE_ID = "metadata.window.table.id"; + public static final String METADATA_WINDOW_TABLE_ID = "metadata.window.table.id"; /** * Distribution set table - Manage metadata id. diff --git a/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties b/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties index 3ead3843d..b67a37593 100644 --- a/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties +++ b/hawkbit-ui/src/main/resources/hawkbit-ui-defaults.properties @@ -12,6 +12,7 @@ vaadin.servlet.productionMode=true vaadin.servlet.urlMapping=/UI/* vaadin.servlet.heartbeatInterval=60 vaadin.servlet.closeIdleSessions=false +server.servlet.session.timeout=300 hawkbit.server.ui.links.documentation.root=https://www.eclipse.org/hawkbit/ hawkbit.server.ui.links.documentation.security=https://www.eclipse.org/hawkbit/concepts/authorization/