diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java index bf5d723a8..e954cec96 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/AmqpConfiguration.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.simulator.amqp; +import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -15,6 +16,7 @@ import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.QueueBuilder; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -65,9 +67,12 @@ public class AmqpConfiguration { * @return the queue */ @Bean - public Queue receiverConnectorQueueFromSp() { - return new Queue(amqpProperties.getReceiverConnectorQueueFromSp(), true, false, false, - getDeadLetterExchangeArgs()); + public Queue receiverConnectorQueueFromHawkBit() { + final Map arguments = getDeadLetterExchangeArgs(); + arguments.putAll(getTTLMaxArgs()); + + return QueueBuilder.nonDurable(amqpProperties.getReceiverConnectorQueueFromSp()).withArguments(arguments) + .build(); } /** @@ -89,7 +94,7 @@ public class AmqpConfiguration { */ @Bean public Binding bindReceiverQueueToSpExchange() { - return BindingBuilder.bind(receiverConnectorQueueFromSp()).to(exchangeQueueToConnector()); + return BindingBuilder.bind(receiverConnectorQueueFromHawkBit()).to(exchangeQueueToConnector()); } /** @@ -99,7 +104,7 @@ public class AmqpConfiguration { */ @Bean public Queue deadLetterQueue() { - return new Queue(amqpProperties.getDeadLetterQueue(), true, false, true); + return QueueBuilder.nonDurable(amqpProperties.getDeadLetterQueue()).withArguments(getTTLMaxArgs()).build(); } /** @@ -145,4 +150,11 @@ public class AmqpConfiguration { return args; } + private static Map getTTLMaxArgs() { + final Map args = new HashMap<>(); + args.put("x-message-ttl", Duration.ofDays(1).toMillis()); + args.put("x-max-length", 100_000); + return args; + } + } diff --git a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java index bd48bbe12..8bb1e1292 100644 --- a/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java +++ b/examples/hawkbit-device-simulator/src/main/java/org/eclipse/hawkbit/simulator/amqp/MessageService.java @@ -82,21 +82,4 @@ public class MessageService { clazz.getTypeName()); return (T) rabbitTemplate.getMessageConverter().fromMessage(message); } - - /** - * Method to verify if lwm2m header is set. - * - * @param message - * the message with the header - * @param header - * the header to verify - */ - public void checkIfLwm2mHeaderEmpty(final Message message, final String header) { - final Object headerObject = message.getMessageProperties().getHeaders().get(header); - if (null == headerObject) { - logAndThrowMessageError(message, "Header of " + header + "empty."); - } - - } - } diff --git a/examples/hawkbit-device-simulator/src/main/resources/logback.xml b/examples/hawkbit-device-simulator/src/main/resources/logback.xml index da64e62d1..469c7bde3 100644 --- a/examples/hawkbit-device-simulator/src/main/resources/logback.xml +++ b/examples/hawkbit-device-simulator/src/main/resources/logback.xml @@ -19,7 +19,6 @@ - diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java index cdbbcba5b..7e2b780b4 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.scheduling.annotation.EnableAsync; * * */ - @Configuration @EnableAsync @ConditionalOnMissingBean(AsyncConfigurer.class) diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java index 35996a114..4425c7278 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/AsyncConfigurerThreadpoolProperties.java @@ -20,7 +20,7 @@ public class AsyncConfigurerThreadpoolProperties { /** * Max queue size for central event executor. */ - private Integer queuesize = 250; + private Integer queuesize = 5_000; /** * Core processing threads for central event executor. @@ -30,7 +30,7 @@ public class AsyncConfigurerThreadpoolProperties { /** * Maximum thread pool size for central event executor. */ - private Integer maxthreads = 50; + private Integer maxthreads = 20; /** * When the number of threads is greater than the core, this is the maximum diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java index 43a096e7d..0aeaf75bb 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/scheduling/ExecutorAutoConfiguration.java @@ -11,7 +11,9 @@ package org.eclipse.hawkbit.autoconfigure.scheduling; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; @@ -21,6 +23,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -39,21 +44,38 @@ public class ExecutorAutoConfiguration { private AsyncConfigurerThreadpoolProperties asyncConfigurerProperties; /** - * @return ExecutorService for general purpose multi threaded operations + * @return ExecutorService with security context availability in thread + * execution.. */ @Bean @ConditionalOnMissingBean public Executor asyncExecutor() { + return new DelegatingSecurityContextExecutor(threadPoolExecutor()); + } + + /** + * @return central ThreadPoolExecutor for general purpose multi threaded + * operations. Tries an orderly shutdown when destroyed. + */ + @Bean(destroyMethod = "shutdown") + public ThreadPoolExecutor threadPoolExecutor() { final BlockingQueue blockingQueue = new ArrayBlockingQueue<>( asyncConfigurerProperties.getQueuesize()); - final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(), + return new ThreadPoolExecutor(asyncConfigurerProperties.getCorethreads(), asyncConfigurerProperties.getMaxthreads(), asyncConfigurerProperties.getIdletimeout(), TimeUnit.MILLISECONDS, blockingQueue, - new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build()); - threadPoolExecutor.setRejectedExecutionHandler((r, executor) -> LOGGER.warn( - "Reject runnable for centralExecutorService, reached limit of queue size {}", - executor.getQueue().size())); - return new DelegatingSecurityContextExecutor(threadPoolExecutor); + new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build(), + new PoolSizeExceededPolicy()); + } + + private static class PoolSizeExceededPolicy extends CallerRunsPolicy { + @Override + public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { + LOGGER.warn( + "Caller has to run on its own instead of centralExecutorService, reached limit of queue size {}", + executor.getQueue().size()); + super.rejectedExecution(r, executor); + } } /** @@ -69,4 +91,32 @@ public class ExecutorAutoConfiguration { return new DelegatingSecurityContextExecutor(threadPoolExecutor); } + /** + * @return {@link TaskExecutor} for task execution + */ + @Bean + @ConditionalOnMissingBean + public TaskExecutor taskExecutor() { + return new ConcurrentTaskExecutor(asyncExecutor()); + } + + /** + * @return {@link ScheduledExecutorService} based on + * {@link #threadPoolTaskScheduler()}. + */ + @Bean + @ConditionalOnMissingBean + public ScheduledExecutorService scheduledExecutorService() { + return threadPoolTaskScheduler().getScheduledExecutor(); + } + + /** + * @return {@link ThreadPoolTaskScheduler} for scheduled operations. + */ + @Bean + @ConditionalOnMissingBean + public ThreadPoolTaskScheduler threadPoolTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } + } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java new file mode 100644 index 000000000..fc979fd67 --- /dev/null +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementConfiguration.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.autoconfigure.security; + +import java.util.ArrayList; + +import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator; +import org.eclipse.hawkbit.im.authentication.PermissionUtils; +import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; +import org.springframework.security.core.Authentication; +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.provisioning.InMemoryUserDetailsManager; + +/** + * Auto-configuration for the in-memory-user-management. + * + */ +@Configuration +@ConditionalOnMissingBean(UserDetailsService.class) +public class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter { + + @Override + public void configure(final AuthenticationManagerBuilder auth) throws Exception { + final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider(); + userDaoAuthenticationProvider.setUserDetailsService(userDetailsService()); + auth.authenticationProvider(userDaoAuthenticationProvider); + } + + /** + * @return the user details service to load a user from memory user manager. + */ + @Bean + @ConditionalOnMissingBean + public UserDetailsService userDetailsService() { + final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager(new ArrayList<>()); + inMemoryUserDetailsManager.setAuthenticationManager(null); + inMemoryUserDetailsManager.createUser(new User("admin", "admin", PermissionUtils.createAllAuthorityList())); + return inMemoryUserDetailsManager; + } + + /** + * @return the multi-tenancy indicator to disallow multi-tenancy + */ + @Bean + @ConditionalOnMissingBean + public MultitenancyIndicator multiTenancyIndicator() { + return () -> false; + } + + private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider { + + @Override + protected Authentication createSuccessAuthentication(final Object principal, + final Authentication authentication, final UserDetails user) { + final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, + authentication.getCredentials(), user.getAuthorities()); + result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false)); + return result; + } + } +} diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java index 8c44f0496..d74b27dc8 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityAutoConfiguration.java @@ -8,43 +8,17 @@ */ package org.eclipse.hawkbit.autoconfigure.security; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.hawkbit.im.authentication.MultitenancyIndicator; import org.eclipse.hawkbit.im.authentication.PermissionService; -import org.eclipse.hawkbit.im.authentication.SpPermission; -import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; -import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter; import org.eclipse.hawkbit.security.DdiSecurityProperties; import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.AuditorAware; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -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.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; /** * {@link EnableAutoConfiguration Auto-configuration} for security. @@ -88,119 +62,4 @@ public class SecurityAutoConfiguration { return new SpringSecurityAuditorAware(); } - /** - * Auto-configuration for the in-memory-user-management. - * - * - * - */ - @Configuration - @ConditionalOnMissingBean(value = { UserAuthenticationFilter.class }) - public static class InMemoryUserManagementConfiguration extends GlobalAuthenticationConfigurerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryUserManagementConfiguration.class); - - @Autowired - private AuthenticationConfiguration configuration; - - /* - * (non-Javadoc) - * - * @see org.springframework.security.config.annotation.authentication. - * configurers. GlobalAuthenticationConfigurerAdapter - * #configure(org.springframework.security.config.annotation. - * authentication.builders.AuthenticationManagerBuilder) - */ - @Override - public void configure(final AuthenticationManagerBuilder auth) throws Exception { - final DaoAuthenticationProvider userDaoAuthenticationProvider = new TenantDaoAuthenticationProvider(); - userDaoAuthenticationProvider.setUserDetailsService(userDetailsService()); - auth.authenticationProvider(userDaoAuthenticationProvider); - } - - /** - * @return the user details service to load a user from memory user - * manager. - */ - @Bean - public UserDetailsService userDetailsService() { - final InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager( - new ArrayList<>()); - inMemoryUserDetailsManager.setAuthenticationManager(null); - inMemoryUserDetailsManager.createUser(new User("admin", "admin", getAllAuthorities())); - return inMemoryUserDetailsManager; - } - - /** - * @return the multi-tenancy indicator to disallow multi-tenancy - */ - @Bean - public MultitenancyIndicator multiTenancyIndicator() { - return new MultitenancyIndicator() { - @Override - public boolean isMultiTenancySupported() { - return false; - } - }; - } - - private Collection getAllAuthorities() { - final List allPermissions = new ArrayList<>(); - final Field[] declaredFields = SpPermission.class.getDeclaredFields(); - for (final Field field : declaredFields) { - if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { - field.setAccessible(true); - try { - final String permissionName = (String) field.get(null); - allPermissions.add(new SimpleGrantedAuthority(permissionName)); - } catch (final IllegalAccessException e) { - LOGGER.error(e.getMessage(), e); - } - } - } - return allPermissions; - } - - private static class TenantDaoAuthenticationProvider extends DaoAuthenticationProvider { - /* - * (non-Javadoc) - * - * @see org.springframework.security.authentication.dao. - * AbstractUserDetailsAuthenticationProvider - * #createSuccessAuthentication(java.lang.Object, - * org.springframework.security.core.Authentication, - * org.springframework.security.core.userdetails.UserDetails) - */ - @Override - protected Authentication createSuccessAuthentication(final Object principal, - final Authentication authentication, final UserDetails user) { - final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, - authentication.getCredentials(), user.getAuthorities()); - result.setDetails(new TenantAwareAuthenticationDetails("DEFAULT", false)); - return result; - } - } - - /** - * @return the {@link UserAuthenticationFilter} to include into the SP - * security configuration. - * @throws Exception - * lazy bean exception maybe if the authentication manager - * cannot be instantiated - */ - @Bean - public UserAuthenticationFilter userAuthenticationFilter() throws Exception { - return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager()); - } - - private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter - implements UserAuthenticationFilter { - - private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) { - super(authenticationManager); - } - - } - } - } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index 825e21c12..fc7a0a1e4 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -8,6 +8,10 @@ */ package org.eclipse.hawkbit.autoconfigure.security; +import static com.google.common.collect.Lists.newArrayList; +import static org.springframework.context.annotation.AdviceMode.ASPECTJ; +import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; + import java.io.IOException; import java.net.URI; @@ -46,18 +50,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.embedded.ServletListenerRegistrationBean; import org.springframework.cache.Cache; -import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.WebSecurityConfigurer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -72,6 +77,8 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter; +import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode; @@ -83,30 +90,49 @@ import org.vaadin.spring.security.web.VaadinRedirectStrategy; import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler; import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler; -import com.google.common.collect.Lists; - /** - * All configurations related to SP authentication and authorization layer. - * - * - * + * All configurations related to HawkBit's authentication and authorization + * layer. */ @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true) +@EnableGlobalMethodSecurity(prePostEnabled = true, mode = ASPECTJ, proxyTargetClass = true, securedEnabled = true) @EnableWebMvcSecurity -@Order(value = Ordered.HIGHEST_PRECEDENCE) +@Order(value = HIGHEST_PRECEDENCE) public class SecurityManagedConfiguration { + private static final Logger LOG = LoggerFactory.getLogger(SecurityManagedConfiguration.class); @Autowired private HawkbitSecurityProperties securityProperties; + @Autowired + private AuthenticationConfiguration configuration; + + /** + * @return the {@link UserAuthenticationFilter} to include into the SP + * security configuration. + * @throws Exception + * lazy bean exception maybe if the authentication manager + * cannot be instantiated + */ + @Bean + @ConditionalOnMissingBean + public UserAuthenticationFilter userAuthenticationFilter() throws Exception { + return new UserAuthenticationFilterBasicAuth(configuration.getAuthenticationManager()); + } + + private static final class UserAuthenticationFilterBasicAuth extends BasicAuthenticationFilter + implements UserAuthenticationFilter { + + private UserAuthenticationFilterBasicAuth(final AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + } + /** * {@link WebSecurityConfigurer} for the internal SP controller API. - * - * - * */ @Configuration @Order(300) @@ -114,19 +140,25 @@ public class SecurityManagedConfiguration { @Autowired private ControllerManagement controllerManagement; + @Autowired private TenantConfigurationManagement tenantConfigurationManagement; + @Autowired private TenantAware tenantAware; + @Autowired private DdiSecurityProperties ddiSecurityConfiguration; + @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + @Autowired private SystemSecurityContext systemSecurityContext; @Override protected void configure(final HttpSecurity http) throws Exception { + final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource(); final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter( @@ -164,16 +196,19 @@ public class SecurityManagedConfiguration { } if (ddiSecurityConfiguration.getAuthentication().getAnonymous().isEnabled()) { + LOG.info( - "******************\n** Anonymous controller security enabled, should only use for developing purposes **\n******************"); + "******************\n** Anonymous controller security enabled, should only be used for developing purposes **\n******************"); + final AnonymousAuthenticationFilter anoymousFilter = new AnonymousAuthenticationFilter( "controllerAnonymousFilter", "anonymous", - Lists.newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), + newArrayList(new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), new SimpleGrantedAuthority(SpringEvalExpressions.CONTROLLER_DOWNLOAD_ROLE))); anoymousFilter.setAuthenticationDetailsSource(authenticationDetailsSource); httpSec.requestMatchers().antMatchers("/*/controller/v1/**", "/*/controller/artifacts/v1/**").and() .securityContext().disable().anonymous().authenticationFilter(anoymousFilter); } else { + httpSec.addFilter(securityHeaderFilter).addFilter(securityTokenFilter) .addFilter(gatewaySecurityTokenFilter).addFilter(controllerAnonymousDownloadFilter) .antMatcher("/*/controller/**").anonymous().disable().authorizeRequests().anyRequest() @@ -186,6 +221,7 @@ public class SecurityManagedConfiguration { @Override protected void configure(final AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider( ddiSecurityConfiguration.getRp().getTrustedIPs())); } @@ -200,6 +236,7 @@ public class SecurityManagedConfiguration { @Bean @Order(50) public FilterRegistrationBean dosFilter() { + final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); filterRegBean.setFilter(new DosFilter(securityProperties.getDos().getFilter().getMaxRead(), @@ -207,6 +244,7 @@ public class SecurityManagedConfiguration { securityProperties.getDos().getFilter().getWhitelist(), securityProperties.getClients().getBlacklist(), securityProperties.getClients().getRemoteIpHeader())); filterRegBean.addUrlPatterns("/{tenant}/controller/v1/*", "/rest/*"); + return filterRegBean; } @@ -219,22 +257,21 @@ public class SecurityManagedConfiguration { @Bean @Order(100) public FilterRegistrationBean eTagFilter() { + final FilterRegistrationBean filterRegBean = new FilterRegistrationBean(); - // eclude the URLs for downloading artifacts, so no eTag is generated in - // the - // ShallowEtagHeaderFilter, just using the SH1 hash of the artifact - // itself as 'ETag', because - // otherwise the file will be copied in memory! + // Exclude the URLs for downloading artifacts, so no eTag is generated + // in the ShallowEtagHeaderFilter, just using the SH1 hash of the + // artifact itself as 'ETag', because otherwise the file will be copied + // in memory! filterRegBean.setFilter(new ExcludePathAwareShallowETagFilter( "/rest/v1/softwaremodules/{smId}/artifacts/{artId}/download", "/{tenant}/controller/artifacts/**", "/{targetid}/softwaremodules/{softwareModuleId}/artifacts/**")); + return filterRegBean; } /** * Security configuration for the REST management API of the health url. - * - * */ @Configuration @Order(310) @@ -249,28 +286,34 @@ public class SecurityManagedConfiguration { /** * Security configuration for the REST management API. - * - * */ @Configuration @Order(350) public static class RestSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { + @Autowired private UserAuthenticationFilter userAuthenticationFilter; + @Autowired private SystemManagement systemManagement; + @Autowired private TenantAware tenantAware; + @Autowired - private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + private SecurityProperties springSecurityProperties; @Override protected void configure(final HttpSecurity http) throws Exception { + final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint(); + basicAuthEntryPoint.setRealmName(springSecurityProperties.getBasic().getRealm()); + HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system.*").csrf().disable(); if (springSecurityProperties.isRequireSsl()) { httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and(); } + httpSec.addFilterBefore(new Filter() { @Override public void init(final FilterConfig filterConfig) throws ServletException { @@ -296,12 +339,13 @@ public class SecurityManagedConfiguration { .hasAnyAuthority(SpPermission.SYSTEM_ADMIN) .antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/**") .hasAnyAuthority(SpPermission.SYSTEM_DIAG); + + httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint); } } /** * {@link WebSecurityConfigurer} for external (management) access. - * */ @Configuration @Order(400) @@ -311,10 +355,13 @@ public class SecurityManagedConfiguration { private static final String XFRAME_OPTION_DENY = "DENY"; private static final String XFRAME_OPTION_SAMEORIGIN = "SAMEORIGIN"; private static final String XFAME_OPTION_ALLOW_FROM = "ALLOW-FROM"; + @Autowired private VaadinSecurityContext vaadinSecurityContext; + @Autowired private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties; + @Autowired private HawkbitSecurityProperties securityProperties; @@ -346,10 +393,13 @@ public class SecurityManagedConfiguration { */ @Bean public VaadinAuthenticationSuccessHandler redirectSaveHandler() { + final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(); + handler.setRedirectStrategy(vaadinRedirectStrategy()); handler.setDefaultTargetUrl("/UI/"); handler.setTargetUrlParameter("r"); + return handler; } @@ -371,7 +421,8 @@ public class SecurityManagedConfiguration { // configuration xframe-option final String confXframeOption = securityProperties.getXframe().getOption(); final String confAllowFromUri = securityProperties.getXframe().getAllowfrom(); - if (confXframeOption.equals(XFAME_OPTION_ALLOW_FROM) && confAllowFromUri.isEmpty()) { + + if (XFAME_OPTION_ALLOW_FROM.equals(confXframeOption) && confAllowFromUri.isEmpty()) { // if allow-from option is specified but no allowFromUri throw // exception throw new IllegalStateException("hawkbit.server.security.xframe.option has been specified as ALLOW-FROM" @@ -380,9 +431,8 @@ public class SecurityManagedConfiguration { } // 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: + // because we bound the vaadin application to /UI and not to root, + // described in vaadin-forum: // https://vaadin.com/forum#!/thread/3200565. HttpSecurity httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$") // disable as CSRF is handled by Vaadin @@ -391,8 +441,9 @@ public class SecurityManagedConfiguration { if (springSecurityProperties.isRequireSsl()) { httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and(); } else { + LOG.info( - "\"******************\\n** Requires HTTPS Security has been disabled for UI, should only use for developing purposes **\\n******************\""); + "\"******************\\n** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **\\n******************\""); } // for UI integrator we allow frame integration on same origin @@ -441,9 +492,6 @@ public class SecurityManagedConfiguration { /** * A Websecruity config to handle and filter the download ids. - * - * - * */ @Configuration @EnableWebSecurity @@ -459,6 +507,7 @@ public class SecurityManagedConfiguration { @Override protected void configure(final HttpSecurity http) throws Exception { + final HttpDownloadAuthenticationFilter downloadIdAuthenticationFilter = new HttpDownloadAuthenticationFilter( downloadIdCache); downloadIdAuthenticationFilter.setAuthenticationManager(authenticationManager()); @@ -476,32 +525,21 @@ public class SecurityManagedConfiguration { auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider( ddiSecurityConfiguration.getRp().getTrustedIPs())); } - } - } /** * 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; - /* - * (non-Javadoc) - * - * @see org.vaadin.spring.security.web.authentication. - * SavedRequestAwareVaadinAuthenticationSuccessHandler - * #onAuthenticationSuccess(org.springframework.security.core. - * Authentication) - */ @Override public void onAuthenticationSuccess(final Authentication authentication) throws Exception { + if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) { systemManagement .getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString()); @@ -515,14 +553,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends // has been fixed. systemManagement.getTenantMetadata("DEFAULT"); } + super.onAuthenticationSuccess(authentication); } } /** * Sevletfilter to create metadata after successful authentication over RESTful. - * - * */ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter { @@ -543,11 +580,13 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter { @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + final String currentTenant = tenantAware.getCurrentTenant(); if (currentTenant != null) { // lazy initialize tenant meta data after successful authentication systemManagement.getTenantMetadata(currentTenant); } + chain.doFilter(request, response); } diff --git a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories index 335054585..7df1f5ed2 100644 --- a/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/hawkbit-autoconfigure/src/main/resources/META-INF/spring.factories @@ -11,4 +11,5 @@ org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.scheduling.AsyncConfigurerAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.cache.RedisAutoConfiguration,\ org.eclipse.hawkbit.autoconfigure.scheduling.ExecutorAutoConfiguration,\ -org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration +org.eclipse.hawkbit.autoconfigure.amqp.AmqpAutoConfiguration,\ +org.eclipse.hawkbit.autoconfigure.security.InMemoryUserManagementConfiguration diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties index 488777b8d..9c197fbb3 100644 --- a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties +++ b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties @@ -7,6 +7,9 @@ # http://www.eclipse.org/legal/epl-v10.html # +# Displayed basic auth realm +security.basic.realm=HawkBit + # JPA / Datasource spring.jpa.eclipselink.eclipselink.weaving=false spring.jpa.database=H2 @@ -27,12 +30,6 @@ vaadin.servlet.urlMapping=/UI/* vaadin.servlet.heartbeatInterval=60 vaadin.servlet.closeIdleSessions=false -# Defines the thread pool executor -hawkbit.threadpool.corethreads=5 -hawkbit.threadpool.maxthreads=20 -hawkbit.threadpool.idletimeout=10000 -hawkbit.threadpool.queuesize=20000 - # Defines the polling time for the controllers in HH:MM:SS notation hawkbit.controller.pollingTime=00:05:00 hawkbit.controller.pollingOverdueTime=00:05:00 diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java index 85a326f9a..75d502c47 100644 --- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactStoreController.java @@ -134,7 +134,7 @@ public class DdiArtifactStoreController implements DdiDlArtifactStoreControllerR private Action checkAndReportDownloadByTarget(final HttpServletRequest request, final String targetid, final LocalArtifact artifact) { final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader())); + IpUtil.getClientIpFromRequest(request, securityProperties)); final Action action = controllerManagement .getActionForDownloadByTargetAndSoftwareModule(target.getControllerId(), artifact.getSoftwareModule()); diff --git a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java index 20d1b2e29..120e6c246 100644 --- a/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java +++ b/hawkbit-ddi-resource/src/main/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootController.java @@ -119,16 +119,14 @@ public class DdiRootController implements DdiRootControllerRestApi { public ResponseEntity getControllerBase(@PathVariable("targetid") final String targetid) { LOG.debug("getControllerBase({})", targetid); - final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.findOrRegisterTargetIfItDoesNotexist(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (target.getTargetInfo().getUpdateStatus() == TargetUpdateStatus.UNKNOWN) { LOG.debug("target with {} extsisted but was in status UNKNOWN -> REGISTERED)", targetid); controllerManagement.updateTargetStatus(target.getTargetInfo(), TargetUpdateStatus.REGISTERED, - System.currentTimeMillis(), - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + System.currentTimeMillis(), IpUtil.getClientIpFromRequest( + requestResponseContextHolder.getHttpServletRequest(), securityProperties)); } return new ResponseEntity<>( @@ -143,9 +141,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @PathVariable("fileName") final String fileName) { ResponseEntity result; - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId); if (checkModule(fileName, module)) { @@ -200,9 +197,8 @@ public class DdiRootController implements DdiRootControllerRestApi { public ResponseEntity downloadArtifactMd5(@PathVariable("targetid") final String targetid, @PathVariable("softwareModuleId") final Long softwareModuleId, @PathVariable("fileName") final String fileName) { - controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final SoftwareModule module = softwareManagement.findSoftwareModuleById(softwareModuleId); @@ -228,9 +224,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @RequestParam(value = "c", required = false, defaultValue = "-1") final int resource) { LOG.debug("getControllerBasedeploymentAction({},{})", targetid, resource); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -263,9 +258,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @PathVariable("targetid") final String targetid, @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("provideBasedeploymentActionFeedback for target [{},{}]: {}", targetid, actionId, feedback); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (!actionId.equals(feedback.getId())) { LOG.warn( @@ -357,9 +351,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @Override public ResponseEntity putConfigData(@Valid @RequestBody final DdiConfigData configData, @PathVariable("targetid") final String targetid) { - controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); controllerManagement.updateControllerAttributes(targetid, configData.getData()); @@ -372,9 +365,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("getControllerCancelAction({})", targetid); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); final Action action = findActionWithExceptionIfNotFound(actionId); if (!action.getTarget().getId().equals(target.getId())) { @@ -403,9 +395,8 @@ public class DdiRootController implements DdiRootControllerRestApi { @PathVariable("actionId") @NotEmpty final Long actionId) { LOG.debug("provideCancelActionFeedback for target [{}]: {}", targetid, feedback); - final Target target = controllerManagement.updateLastTargetQuery(targetid, - IpUtil.getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), - securityProperties.getClients().getRemoteIpHeader())); + final Target target = controllerManagement.updateLastTargetQuery(targetid, IpUtil + .getClientIpFromRequest(requestResponseContextHolder.getHttpServletRequest(), securityProperties)); if (!actionId.equals(feedback.getId())) { LOG.warn( diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java index b3828582c..7f12b78ae 100644 --- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiArtifactDownloadTest.java @@ -29,11 +29,11 @@ import org.apache.commons.lang3.RandomUtils; import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; import org.junit.Test; import org.slf4j.LoggerFactory; diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java index 135754604..31ec37c58 100644 --- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java @@ -28,14 +28,16 @@ import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; @@ -50,6 +52,9 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("Root Poll Resource") public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoDB { + @Autowired + private HawkbitSecurityProperties securityProperties; + @Test @Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.") @WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = "ROLE_CONTROLLER", autoCreateTenant = false) @@ -257,6 +262,23 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD } + @Test + @Description("Ensures that the source IP address of the polling target is not stored in repository if disabled") + public void rootRsIpAddressNotStoredIfDisabled() throws Exception { + securityProperties.getClients().setTrackRemoteIp(false); + + // test + final String knownControllerId1 = "0815"; + mvc.perform(get("/{tenant}/controller/v1/{controllerId}", tenantAware.getCurrentTenant(), knownControllerId1)) + .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()); + + // verify + final Target target = targetManagement.findTargetByControllerID(knownControllerId1); + assertThat(target.getTargetInfo().getAddress()).isEqualTo(IpUtil.createHttpUri("***")); + + securityProperties.getClients().setTrackRemoteIp(true); + } + @Test @Description("Controller trys to finish an update process after it has been finished by an error action status.") public void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception { diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java index 20a11713f..e40d9bd3c 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpConfiguration.java @@ -8,21 +8,32 @@ */ package org.eclipse.hawkbit.amqp; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; + import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.amqp.RabbitProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.retry.backoff.ExponentialBackOffPolicy; +import org.springframework.retry.support.RetryTemplate;; /** * The spring AMQP configuration which is enabled by using the profile @@ -32,14 +43,69 @@ import org.springframework.context.annotation.Bean; @EnableConfigurationProperties({ AmqpProperties.class, AmqpDeadletterProperties.class }) public class AmqpConfiguration { - @Autowired - protected AmqpProperties amqpProperties; + private static final Logger LOGGER = LoggerFactory.getLogger(AmqpConfiguration.class); @Autowired - protected AmqpDeadletterProperties amqpDeadletterProperties; + private AmqpProperties amqpProperties; @Autowired - private ConnectionFactory connectionFactory; + private AmqpDeadletterProperties amqpDeadletterProperties; + + @Autowired + @Qualifier("threadPoolExecutor") + private ThreadPoolExecutor threadPoolExecutor; + + @Autowired + private ConnectionFactory rabbitConnectionFactory; + + @Configuration + @ConditionalOnMissingBean(ConnectionFactory.class) + protected static class RabbitConnectionFactoryCreator { + + @Autowired + private AmqpProperties amqpProperties; + + @Autowired + @Qualifier("threadPoolExecutor") + private ThreadPoolExecutor threadPoolExecutor; + + @Autowired + private ScheduledExecutorService scheduledExecutorService; + + /** + * {@link ConnectionFactory} with enabled publisher confirms and + * heartbeat. + * + * @param config + * with standard {@link RabbitProperties} + * @return {@link ConnectionFactory} + */ + @Bean + public ConnectionFactory rabbitConnectionFactory(final RabbitProperties config) { + final CachingConnectionFactory factory = new CachingConnectionFactory(); + factory.setRequestedHeartBeat(amqpProperties.getRequestedHeartBeat()); + factory.setExecutor(threadPoolExecutor); + factory.getRabbitConnectionFactory().setHeartbeatExecutor(scheduledExecutorService); + factory.setPublisherConfirms(true); + + final String addresses = config.getAddresses(); + factory.setAddresses(addresses); + if (config.getHost() != null) { + factory.setHost(config.getHost()); + factory.setPort(config.getPort()); + } + if (config.getUsername() != null) { + factory.setUsername(config.getUsername()); + } + if (config.getPassword() != null) { + factory.setPassword(config.getPassword()); + } + if (config.getVirtualHost() != null) { + factory.setVirtualHost(config.getVirtualHost()); + } + return factory; + } + } /** * Create a {@link RabbitAdmin} and ignore declaration exceptions. @@ -49,20 +115,32 @@ public class AmqpConfiguration { */ @Bean public RabbitAdmin rabbitAdmin() { - final RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); + final RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitConnectionFactory); rabbitAdmin.setIgnoreDeclarationExceptions(true); return rabbitAdmin; } /** - * Method to set the Jackson2JsonMessageConverter. - * - * @return the Jackson2JsonMessageConverter + * @return {@link RabbitTemplate} with automatic retry, published confirms + * and {@link Jackson2JsonMessageConverter}. */ @Bean public RabbitTemplate rabbitTemplate() { - final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + final RabbitTemplate rabbitTemplate = new RabbitTemplate(rabbitConnectionFactory); rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter()); + + final RetryTemplate retryTemplate = new RetryTemplate(); + retryTemplate.setBackOffPolicy(new ExponentialBackOffPolicy()); + rabbitTemplate.setRetryTemplate(retryTemplate); + + rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> { + if (ack) { + LOGGER.debug("Message with {} confirmed by broker.", correlationData); + } else { + LOGGER.error("Broker is unable to handle message with {} : {}", correlationData, cause); + } + }); + return rabbitTemplate; } @@ -159,7 +237,7 @@ public class AmqpConfiguration { public SimpleRabbitListenerContainerFactory listenerContainerFactory() { final SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory(); containerFactory.setDefaultRequeueRejected(false); - containerFactory.setConnectionFactory(connectionFactory); + containerFactory.setConnectionFactory(rabbitConnectionFactory); containerFactory.setMissingQueuesFatal(amqpProperties.isMissingQueuesFatal()); return containerFactory; } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java index ce6068ce8..f9b4cceb6 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpProperties.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.amqp; +import java.util.concurrent.TimeUnit; + import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -38,6 +40,11 @@ public class AmqpProperties { */ private boolean missingQueuesFatal = false; + /** + * Requested heartbeat interval from broker in {@link TimeUnit#SECONDS}. + */ + private int requestedHeartBeat = (int) TimeUnit.SECONDS.toSeconds(60); + /** * Is missingQueuesFatal enabled * @@ -102,4 +109,13 @@ public class AmqpProperties { public void setReceiverQueue(final String receiverQueue) { this.receiverQueue = receiverQueue; } + + public int getRequestedHeartBeat() { + return requestedHeartBeat; + } + + public void setRequestedHeartBeat(final int requestedHeartBeat) { + this.requestedHeartBeat = requestedHeartBeat; + } + } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java index 76870ac93..2c8feda13 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/BaseAmqpService.java @@ -109,7 +109,7 @@ public class BaseAmqpService { } protected final void logAndThrowMessageError(final Message message, final String error) { - LOGGER.warn("Error \"{}\" reported by message: {}", error, message); + LOGGER.warn("Warning! \"{}\" reported by message: {}", error, message); throw new IllegalArgumentException(error); } diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java index 244544b64..afb3e7ff2 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/DefaultAmqpSenderService.java @@ -9,10 +9,14 @@ package org.eclipse.hawkbit.amqp; import java.net.URI; +import java.util.UUID; import org.eclipse.hawkbit.util.IpUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.rabbit.support.CorrelationData; /** * A default implementation for the sender service. The service sends all amqp @@ -20,6 +24,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; * extracted from the uri. */ public class DefaultAmqpSenderService implements AmqpSenderService { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAmqpSenderService.class); private final RabbitTemplate internalAmqpTemplate; @@ -39,7 +44,16 @@ public class DefaultAmqpSenderService implements AmqpSenderService { return; } - internalAmqpTemplate.send(extractExchange(replyTo), null, message); + final String correlationId = UUID.randomUUID().toString(); + final String exchange = extractExchange(replyTo); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Sending message {} to exchange {} with correlationId {}", message, exchange, correlationId); + } else { + LOGGER.debug("Sending message to exchange {} with correlationId {}", exchange, correlationId); + } + + internalAmqpTemplate.send(exchange, null, message, new CorrelationData(correlationId)); } } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java index c9be9ffa6..075313a19 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/AmqpTestConfiguration.java @@ -8,6 +8,14 @@ */ package org.eclipse.hawkbit; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.amqp.AmqpProperties; import org.eclipse.hawkbit.amqp.AmqpSenderService; import org.eclipse.hawkbit.amqp.DefaultAmqpSenderService; import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder; @@ -16,13 +24,22 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.security.concurrent.DelegatingSecurityContextExecutor; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; /** * */ @Configuration +@EnableConfigurationProperties({ AmqpProperties.class }) public class AmqpTestConfiguration { /** * @return the {@link SystemSecurityContext} singleton bean which make it @@ -56,4 +73,55 @@ public class AmqpTestConfiguration { public AmqpSenderService amqpSenderServiceBean(final RabbitTemplate rabbitTemplate) { return new DefaultAmqpSenderService(rabbitTemplate); } + + /** + * @return ExecutorService with security context availability in thread + * execution.. + */ + @Bean + @ConditionalOnMissingBean + public Executor asyncExecutor() { + return new DelegatingSecurityContextExecutor(threadPoolExecutor()); + } + + /** + * @return central ThreadPoolExecutor for general purpose multi threaded + * operations. Tries an orderly shutdown when destroyed. + */ + @Bean(destroyMethod = "shutdown") + public ThreadPoolExecutor threadPoolExecutor() { + final BlockingQueue blockingQueue = new ArrayBlockingQueue<>(10); + final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 10, 1000, TimeUnit.MILLISECONDS, + blockingQueue, new ThreadFactoryBuilder().setNameFormat("central-executor-pool-%d").build()); + + return threadPoolExecutor; + } + + /** + * @return {@link TaskExecutor} for task execution + */ + @Bean + @ConditionalOnMissingBean + public TaskExecutor taskExecutor() { + return new ConcurrentTaskExecutor(asyncExecutor()); + } + + /** + * @return {@link ScheduledExecutorService} based on + * {@link #threadPoolTaskScheduler()}. + */ + @Bean + @ConditionalOnMissingBean + public ScheduledExecutorService scheduledExecutorService() { + return threadPoolTaskScheduler().getScheduledExecutor(); + } + + /** + * @return {@link ThreadPoolTaskScheduler} for scheduled operations. + */ + @Bean + @ConditionalOnMissingBean + public ThreadPoolTaskScheduler threadPoolTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } } diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java index 5faaa74f0..103dc6c57 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherServiceTest.java @@ -37,7 +37,7 @@ import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; import org.mockito.ArgumentCaptor; diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java index c67d6cf47..e93e1340f 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/util/PropertyBasedArtifactUrlHandlerTest.java @@ -16,7 +16,7 @@ import org.eclipse.hawkbit.api.UrlProtocol; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -33,6 +33,7 @@ import ru.yandex.qatools.allure.annotations.Stories; @Stories("Test to generate the artifact download URL") @SpringApplicationConfiguration(classes = { AmqpTestConfiguration.class, org.eclipse.hawkbit.RepositoryApplicationConfiguration.class }) + public class PropertyBasedArtifactUrlHandlerTest extends AbstractIntegrationTestWithMongoDB { private static final String HTTPS_LOCALHOST = "https://localhost:8080/"; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java index ad72aa55d..556454f93 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetResourceTest.java @@ -29,12 +29,12 @@ import java.util.Set; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.util.TestdataFactory; -import org.eclipse.hawkbit.repository.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java index ad6be0854..bc6d69cd3 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtDistributionSetTypeResourceTest.java @@ -27,7 +27,7 @@ import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java index ff49542ce..11536e6e1 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtRolloutResourceTest.java @@ -29,7 +29,7 @@ import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java index e7397dd49..79a3fc2b2 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleResourceTest.java @@ -41,8 +41,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.util.HashGeneratorUtils; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB; import org.eclipse.hawkbit.rest.json.model.ExceptionInfo; import org.eclipse.hawkbit.rest.util.JsonBuilder; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java index 363b12cde..36d975138 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSoftwareModuleTypeResourceTest.java @@ -26,7 +26,7 @@ import java.util.List; import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java index 6e50d1103..1375307d4 100644 --- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java +++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java @@ -40,7 +40,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.Status; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.ActionStatus; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; diff --git a/hawkbit-repository/README.md b/hawkbit-repository/README.md new file mode 100644 index 000000000..2d68a4e73 --- /dev/null +++ b/hawkbit-repository/README.md @@ -0,0 +1,47 @@ +# hawkBit metadata repository + +The repository is in charge for managing the meta data of the update server, e.g. provisioning targets, distribution sets, software modules etc. + +# Build + +[indent=0] +---- + $ mvn clean install +---- + +Note, in order to build correctly in your IDE, you have to add ./target/generated-sources/apt to your build path. + +#Concepts + +## Rollout +A rollout consists of the distribution set and a target-query-filter which defines the targets to be updated in this rollout. The targets within this filter are split up in configured amount of _Deployment Groups_ at creation time. + +When starting a rollout, for all targets within this rollout deployment actions will be created. The deployment actions of the first group will be started immediately all other deployment actions will be scheduled. + +> Due rollouts might include a large number of targets and deployment group, creation as well as starting a rollout might take some time and therefore the creation and starting of an rollout is executed asynchronously. The creation and starting progress is reflected by the rollout's status attribute + +### Rollout Creation +The targets reflected by the target-query-filter is interpreted at creation time. Only targets which have been created at that time are included in the rollout. Targets which are created after the rollout creation will not be included. At rollout creation time all necessary deployment groups containing the targets will be created. Dynamically adding targets to a created or running rollout is currently not supported. + +### Rollout Starting +The rollout is using the same concept based on _deployment acionts_ per target. All necessary _deployment acionts_ will be created at starting point but not all _deployment acionts_ will be set to running. Only the _deployment acionts_ of the first _deployment group_ is set to running, all other actions are created in _scheduled_ state. +If targets having not finished _deployment actions_ at rollout starting time, these action are tried to cancel (state: canceling). Scheduled actions from another rollout are canceled directly on server side because they were never running before and can be safely canceled. + +>Multiple rollouts can be running at the same time, but if the rollouts effect the same targets they will interfer the targets _deployment actions_ e.g. canceling/cancel already running/scheduled _deployment actions_. + +### Deployment Group Condition/Action +#### Success Condition/Action +A _success condition_ defines when a deployment group is interpreted as success and triggers the _success action_. E.g. a threshold of successfully updated targets within the group. + +The _success action_ is executed if the _success_condition_ is fullfilled. Currently only the _success action_ starting the next following deployment group is available. + +#### Error Condition/Action +A _error condition_ defines when a deployment group is interpreted as failure and triggers the _error action_. E.g. a threshold of update failures of targets within the group. + +The _error action_ is executed if the _error condition_ is fullfilled. Currently only the _error action_ pausing the whole rollout is available, a paused rollout can be resumed by a user. + +### Rollout Scheduler +The rollout is managed by a scheduler task which is checking for rollouts in _running_ state. This is done atomic by updating the row in the database, so only the rollouts are checked and processed for the current instance to avoid that multiple instances are processing a rollout. + +>Due the scheduler, it might take some time until a rollouts is processed and switching is state or starting the next deployment group. + diff --git a/hawkbit-repository/hawkbit-repository-api/README.md b/hawkbit-repository/hawkbit-repository-api/README.md new file mode 100644 index 000000000..8000ad390 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/README.md @@ -0,0 +1,6 @@ +# hawkBit repository API + +API for repository access. Contains: + +- Entity Model +- Management service API \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java index 9a1e442b0..5dcb26638 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/Constants.java @@ -33,7 +33,7 @@ public final class Constants { * generated by repository for every new account for "Firmware/Operating * System" . */ - public static final String SMT_DEFAULT_OS_NAME = "Firmware"; + public static final String SMT_DEFAULT_OS_NAME = "OS"; /** * {@link SoftwareModuleType#getName()} of a {@link SoftwareModuleType} * generated by repository for every new account for "applications/apps". diff --git a/hawkbit-repository/hawkbit-repository-core/README.md b/hawkbit-repository/hawkbit-repository-core/README.md new file mode 100644 index 000000000..6973d7406 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-core/README.md @@ -0,0 +1,3 @@ +# hawkBit common implementation + +Core elements that can be used by implementations. \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/README.md b/hawkbit-repository/hawkbit-repository-jpa/README.md index 2d68a4e73..6dd0217e7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/README.md +++ b/hawkbit-repository/hawkbit-repository-jpa/README.md @@ -1,47 +1,3 @@ -# hawkBit metadata repository - -The repository is in charge for managing the meta data of the update server, e.g. provisioning targets, distribution sets, software modules etc. - -# Build - -[indent=0] ----- - $ mvn clean install ----- - -Note, in order to build correctly in your IDE, you have to add ./target/generated-sources/apt to your build path. - -#Concepts - -## Rollout -A rollout consists of the distribution set and a target-query-filter which defines the targets to be updated in this rollout. The targets within this filter are split up in configured amount of _Deployment Groups_ at creation time. - -When starting a rollout, for all targets within this rollout deployment actions will be created. The deployment actions of the first group will be started immediately all other deployment actions will be scheduled. - -> Due rollouts might include a large number of targets and deployment group, creation as well as starting a rollout might take some time and therefore the creation and starting of an rollout is executed asynchronously. The creation and starting progress is reflected by the rollout's status attribute - -### Rollout Creation -The targets reflected by the target-query-filter is interpreted at creation time. Only targets which have been created at that time are included in the rollout. Targets which are created after the rollout creation will not be included. At rollout creation time all necessary deployment groups containing the targets will be created. Dynamically adding targets to a created or running rollout is currently not supported. - -### Rollout Starting -The rollout is using the same concept based on _deployment acionts_ per target. All necessary _deployment acionts_ will be created at starting point but not all _deployment acionts_ will be set to running. Only the _deployment acionts_ of the first _deployment group_ is set to running, all other actions are created in _scheduled_ state. -If targets having not finished _deployment actions_ at rollout starting time, these action are tried to cancel (state: canceling). Scheduled actions from another rollout are canceled directly on server side because they were never running before and can be safely canceled. - ->Multiple rollouts can be running at the same time, but if the rollouts effect the same targets they will interfer the targets _deployment actions_ e.g. canceling/cancel already running/scheduled _deployment actions_. - -### Deployment Group Condition/Action -#### Success Condition/Action -A _success condition_ defines when a deployment group is interpreted as success and triggers the _success action_. E.g. a threshold of successfully updated targets within the group. - -The _success action_ is executed if the _success_condition_ is fullfilled. Currently only the _success action_ starting the next following deployment group is available. - -#### Error Condition/Action -A _error condition_ defines when a deployment group is interpreted as failure and triggers the _error action_. E.g. a threshold of update failures of targets within the group. - -The _error action_ is executed if the _error condition_ is fullfilled. Currently only the _error action_ pausing the whole rollout is available, a paused rollout can be resumed by a user. - -### Rollout Scheduler -The rollout is managed by a scheduler task which is checking for rollouts in _running_ state. This is done atomic by updating the row in the database, so only the rollouts are checked and processed for the current instance to avoid that multiple instances are processing a rollout. - ->Due the scheduler, it might take some time until a rollouts is processed and switching is state or starting the next deployment group. +# hawkBit JPA implementation +JPA implementation of the repository. Based on [EclipseLink](http://www.eclipse.org/eclipselink/) and [Spring Data Jpa](http://projects.spring.io/spring-data-jpa/). \ No newline at end of file diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java index 50207037a..469e84681 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/RepositoryApplicationConfiguration.java @@ -11,8 +11,36 @@ package org.eclipse.hawkbit; import java.util.HashMap; import java.util.Map; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.ControllerManagement; +import org.eclipse.hawkbit.repository.DeploymentManagement; +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.ReportManagement; +import org.eclipse.hawkbit.repository.RolloutGroupManagement; +import org.eclipse.hawkbit.repository.RolloutManagement; +import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SystemManagement; +import org.eclipse.hawkbit.repository.TagManagement; +import org.eclipse.hawkbit.repository.TargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; +import org.eclipse.hawkbit.repository.TenantStatsManagement; +import org.eclipse.hawkbit.repository.jpa.JpaArtifactManagement; +import org.eclipse.hawkbit.repository.jpa.JpaControllerManagement; +import org.eclipse.hawkbit.repository.jpa.JpaDeploymentManagement; +import org.eclipse.hawkbit.repository.jpa.JpaDistributionSetManagement; +import org.eclipse.hawkbit.repository.jpa.JpaEntityFactory; +import org.eclipse.hawkbit.repository.jpa.JpaReportManagement; +import org.eclipse.hawkbit.repository.jpa.JpaRolloutGroupManagement; +import org.eclipse.hawkbit.repository.jpa.JpaRolloutManagement; +import org.eclipse.hawkbit.repository.jpa.JpaSoftwareManagement; +import org.eclipse.hawkbit.repository.jpa.JpaSystemManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTagManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTargetFilterQueryManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTargetManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTenantConfigurationManagement; +import org.eclipse.hawkbit.repository.jpa.JpaTenantStatsManagement; import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler; import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager; import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; @@ -26,6 +54,7 @@ import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -35,6 +64,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; @@ -50,6 +80,7 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess @Configuration @ComponentScan @EnableAutoConfiguration +@EnableScheduling public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { /** * @return the {@link SystemSecurityContext} singleton bean which make it @@ -173,4 +204,170 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { public PlatformTransactionManager transactionManager() { return new MultiTenantJpaTransactionManager(); } + + /** + * {@link JpaSystemManagement} bean. + * + * @return a new {@link SystemManagement} + */ + @Bean + @ConditionalOnMissingBean + public SystemManagement systemManagement() { + return new JpaSystemManagement(); + } + + /** + * {@link JpaReportManagement} bean. + * + * @return a new {@link ReportManagement} + */ + @Bean + @ConditionalOnMissingBean + public ReportManagement reportManagement() { + return new JpaReportManagement(); + } + + /** + * {@link JpaDistributionSetManagement} bean. + * + * @return a new {@link DistributionSetManagement} + */ + @Bean + @ConditionalOnMissingBean + public DistributionSetManagement distributionSetManagement() { + return new JpaDistributionSetManagement(); + } + + /** + * {@link JpaTenantStatsManagement} bean. + * + * @return a new {@link TenantStatsManagement} + */ + @Bean + @ConditionalOnMissingBean + public TenantStatsManagement tenantStatsManagement() { + return new JpaTenantStatsManagement(); + } + + /** + * {@link JpaTenantConfigurationManagement} bean. + * + * @return a new {@link TenantConfigurationManagement} + */ + @Bean + @ConditionalOnMissingBean + public TenantConfigurationManagement tenantConfigurationManagement() { + return new JpaTenantConfigurationManagement(); + } + + /** + * {@link JpaTenantConfigurationManagement} bean. + * + * @return a new {@link TenantConfigurationManagement} + */ + @Bean + @ConditionalOnMissingBean + public TargetManagement targetManagement() { + return new JpaTargetManagement(); + } + + /** + * {@link JpaTargetFilterQueryManagement} bean. + * + * @return a new {@link TargetFilterQueryManagement} + */ + @Bean + @ConditionalOnMissingBean + public TargetFilterQueryManagement targetFilterQueryManagement() { + return new JpaTargetFilterQueryManagement(); + } + + /** + * {@link JpaTagManagement} bean. + * + * @return a new {@link TagManagement} + */ + @Bean + @ConditionalOnMissingBean + public TagManagement tagManagement() { + return new JpaTagManagement(); + } + + /** + * {@link JpaSoftwareManagement} bean. + * + * @return a new {@link SoftwareManagement} + */ + @Bean + @ConditionalOnMissingBean + public SoftwareManagement softwareManagement() { + return new JpaSoftwareManagement(); + } + + /** + * {@link JpaRolloutManagement} bean. + * + * @return a new {@link RolloutManagement} + */ + @Bean + @ConditionalOnMissingBean + public RolloutManagement rolloutManagement() { + return new JpaRolloutManagement(); + } + + /** + * {@link JpaRolloutGroupManagement} bean. + * + * @return a new {@link RolloutGroupManagement} + */ + @Bean + @ConditionalOnMissingBean + public RolloutGroupManagement rolloutGroupManagement() { + return new JpaRolloutGroupManagement(); + } + + /** + * {@link JpaDeploymentManagement} bean. + * + * @return a new {@link DeploymentManagement} + */ + @Bean + @ConditionalOnMissingBean + public DeploymentManagement deploymentManagement() { + return new JpaDeploymentManagement(); + } + + /** + * {@link JpaControllerManagement} bean. + * + * @return a new {@link ControllerManagement} + */ + @Bean + @ConditionalOnMissingBean + public ControllerManagement controllerManagement() { + return new JpaControllerManagement(); + } + + /** + * {@link JpaArtifactManagement} bean. + * + * @return a new {@link ArtifactManagement} + */ + + @Bean + @ConditionalOnMissingBean + public ArtifactManagement artifactManagement() { + return new JpaArtifactManagement(); + } + + /** + * {@link JpaEntityFactory} bean. + * + * @return a new {@link EntityFactory} + */ + @Bean + @ConditionalOnMissingBean + public EntityFactory entityFactory() { + return new JpaEntityFactory(); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java index 1ab6cbe08..83791a66d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DistributionSetRepository.java @@ -16,7 +16,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Tag; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -82,15 +84,26 @@ public interface DistributionSetRepository List findByModules(JpaSoftwareModule module); /** - * Finds {@link DistributionSet}s based on given ID if they are not assigned - * yet to an {@link UpdateAction}, i.e. unused. + * Finds {@link DistributionSet}s based on given ID that are assigned yet to + * an {@link Action}, i.e. in use. * * @param ids * to search for - * @return + * @return list of {@link DistributionSet#getId()} */ @Query("select ac.distributionSet.id from JpaAction ac where ac.distributionSet.id in :ids") - List findAssignedDistributionSetsById(@Param("ids") Long... ids); + List findAssignedToTargetDistributionSetsById(@Param("ids") Long... ids); + + /** + * Finds {@link DistributionSet}s based on given ID that are assigned yet to + * an {@link Rollout}, i.e. in use. + * + * @param ids + * to search for + * @return list of {@link DistributionSet#getId()} + */ + @Query("select ra.distributionSet.id from JpaRollout ra where ra.distributionSet.id in :ids") + List findAssignedToRolloutDistributionSetsById(@Param("ids") Long... ids); /** * Saves all given {@link DistributionSet}s. diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java index ea0e5c34f..3c94d885b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaArtifactManagement.java @@ -41,7 +41,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -52,7 +51,6 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaArtifactManagement implements ArtifactManagement { private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 77b71e661..255fef2ae 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -54,7 +54,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -65,7 +64,6 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaControllerManagement implements ControllerManagement { private static final Logger LOG = LoggerFactory.getLogger(ControllerManagement.class); private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java index 4739f16a7..6236e8d6f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDeploymentManagement.java @@ -96,7 +96,6 @@ import com.google.common.eventbus.EventBus; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaDeploymentManagement implements DeploymentManagement { private static final Logger LOG = LoggerFactory.getLogger(JpaDeploymentManagement.class); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index e5a38cf51..0e97d6ff5 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -60,7 +60,6 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -74,7 +73,6 @@ import com.google.common.eventbus.EventBus; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired @@ -173,7 +171,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { public void deleteDistributionSet(final Long... distributionSetIDs) { final List toHardDelete = new ArrayList<>(); - final List assigned = distributionSetRepository.findAssignedDistributionSetsById(distributionSetIDs); + final List assigned = distributionSetRepository + .findAssignedToTargetDistributionSetsById(distributionSetIDs); + assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs)); // soft delete assigned if (!assigned.isEmpty()) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java index afa3b4dc6..a3792de54 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaEntityFactory.java @@ -42,13 +42,11 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetFilterQuery; import org.eclipse.hawkbit.repository.model.TargetTag; -import org.springframework.stereotype.Service; /** * JPA Implementation of {@link EntityFactory}. * */ -@Service public class JpaEntityFactory implements EntityFactory { @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java index 76eb04a34..c6795f600 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaReportManagement.java @@ -45,7 +45,6 @@ import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -56,7 +55,6 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaReportManagement implements ReportManagement { @Value("${spring.jpa.database}") diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java index 7d176d40a..9f63204b1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutGroupManagement.java @@ -47,7 +47,6 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -56,7 +55,6 @@ import org.springframework.validation.annotation.Validated; * JPA implementation of {@link RolloutGroupManagement}. */ @Validated -@Service @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public class JpaRolloutGroupManagement implements RolloutGroupManagement { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index d412d2164..239302a70 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -60,8 +60,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.Isolation; @@ -76,8 +74,6 @@ import org.springframework.validation.annotation.Validated; * JPA implementation of {@link RolloutManagement}. */ @Validated -@Service -@EnableScheduling @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public class JpaRolloutManagement implements RolloutManagement { private static final Logger LOGGER = LoggerFactory.getLogger(RolloutManagement.class); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index 2fc057aec..50127e227 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -60,7 +60,6 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -74,7 +73,6 @@ import com.google.common.collect.Sets; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaSoftwareManagement implements SoftwareManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java index 3fed3d858..ea6c99708 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java @@ -8,7 +8,6 @@ */ package org.eclipse.hawkbit.repository.jpa; -import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; @@ -34,10 +33,8 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.interceptor.KeyGenerator; -import org.springframework.cache.interceptor.SimpleKeyGenerator; -import org.springframework.context.annotation.Bean; +import org.springframework.context.ApplicationContext; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -49,7 +46,6 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, SystemManagement { @Autowired private EntityManager entityManager; @@ -108,7 +104,11 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst @Autowired private TenancyCacheManager cacheManager; - private final ThreadLocal createInitialTenant = new ThreadLocal<>(); + @Autowired + private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator; + + @Autowired + private ApplicationContext applicationContext; @Override public SystemUsageReport getSystemUsageStatistics() { @@ -154,9 +154,8 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst @Override @Transactional(propagation = Propagation.SUPPORTS) - @Bean public KeyGenerator currentTenantKeyGenerator() { - return new CurrentTenantKeyGenerator(); + return currentTenantCacheKeyGenerator.currentTenantKeyGenerator(); } @Override @@ -169,11 +168,12 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst // Create if it does not exist if (result == null) { try { - createInitialTenant.set(tenant); + currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant); cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null)); + applicationContext.getBean("currentTenantKeyGenerator"); return tenantMetaDataRepository.save(new JpaTenantMetaData(createStandardSoftwareDataSetup(), tenant)); } finally { - createInitialTenant.remove(); + currentTenantCacheKeyGenerator.getCreateInitialTenant().remove(); } } @@ -239,7 +239,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst // tenant is not cached anyway already. @Transactional(propagation = Propagation.NOT_SUPPORTED, isolation = Isolation.READ_UNCOMMITTED) public String currentTenant() { - final String initialTenantCreation = createInitialTenant.get(); + final String initialTenantCreation = currentTenantCacheKeyGenerator.getCreateInitialTenant().get(); if (initialTenantCreation == null) { final TenantMetaData findByTenant = tenantMetaDataRepository .findByTenantIgnoreCase(tenantAware.getCurrentTenant()); @@ -260,29 +260,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst return tenantMetaDataRepository.save((JpaTenantMetaData) metaData); } - /** - * A implementation of the {@link KeyGenerator} to generate a key based on - * either the {@code createInitialTenant} thread local and the - * {@link TenantAware}, but in case we are in a tenant creation with its - * default types we need to use the tenant the current tenant which is - * currently created and not the one currently in the {@link TenantAware}. - * - */ - public class CurrentTenantKeyGenerator implements KeyGenerator { - @Override - // Exception squid:S923 - override - @SuppressWarnings({ "squid:S923" }) - public Object generate(final Object target, final Method method, final Object... params) { - final String initialTenantCreation = createInitialTenant.get(); - if (initialTenantCreation == null) { - return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(), - tenantAware.getCurrentTenant().toUpperCase()); - } - return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(), - initialTenantCreation.toUpperCase()); - } - } - private DistributionSetType createStandardSoftwareDataSetup() { final SoftwareModuleType app = softwareModuleTypeRepository .save(new JpaSoftwareModuleType(Constants.SMT_DEFAULT_APP_KEY, Constants.SMT_DEFAULT_APP_NAME, diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java index 29fbb8a2b..e881d8ef8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTagManagement.java @@ -39,7 +39,6 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -52,7 +51,6 @@ import com.google.common.eventbus.EventBus; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaTagManagement implements TagManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java index f418f5f4b..65ed6faa4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetFilterQueryManagement.java @@ -40,7 +40,6 @@ import com.google.common.base.Strings; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaTargetFilterQueryManagement implements TargetFilterQueryManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 892ddc771..b7a2facc8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -59,7 +59,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -75,7 +74,6 @@ import com.google.common.eventbus.EventBus; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaTargetManagement implements TargetManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java index 9f65091a4..d5d6a5540 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java @@ -23,7 +23,6 @@ import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.Modifying; -import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -33,7 +32,6 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -@Service public class JpaTenantConfigurationManagement implements EnvironmentAware, TenantConfigurationManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java index e3866a8ad..75f99d886 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantStatsManagement.java @@ -24,7 +24,6 @@ import org.springframework.validation.annotation.Validated; * */ @Validated -@Service public class JpaTenantStatsManagement implements TenantStatsManagement { @Autowired diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java new file mode 100644 index 000000000..2bed4aeff --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/SystemManagementCacheKeyGenerator.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import java.lang.reflect.Method; + +import org.eclipse.hawkbit.tenancy.TenantAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.cache.interceptor.SimpleKeyGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Service; + +/** + * Implementation of {@link CurrentTenantCacheKeyGenerator}. + * + */ +@Service +public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator { + + @Autowired + private TenantAware tenantAware; + + private final ThreadLocal createInitialTenant = new ThreadLocal<>(); + + /** + * A implementation of the {@link KeyGenerator} to generate a key based on + * either the {@code createInitialTenant} thread local and the + * {@link TenantAware}, but in case we are in a tenant creation with its + * default types we need to use the tenant the current tenant which is + * currently created and not the one currently in the {@link TenantAware}. + * + */ + public class CurrentTenantKeyGenerator implements KeyGenerator { + @Override + // Exception squid:S923 - override + @SuppressWarnings({ "squid:S923" }) + public Object generate(final Object target, final Method method, final Object... params) { + final String initialTenantCreation = createInitialTenant.get(); + if (initialTenantCreation == null) { + return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(), + tenantAware.getCurrentTenant().toUpperCase()); + } + return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(), + initialTenantCreation.toUpperCase()); + } + } + + @Override + @Bean + public KeyGenerator currentTenantKeyGenerator() { + return new CurrentTenantKeyGenerator(); + } + + ThreadLocal getCreateInitialTenant() { + return createInitialTenant; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java index b4b451ecd..45831d08f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java @@ -12,7 +12,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTest; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.data.mongodb.gridfs.GridFsOperations; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java index d1c433cc4..e2e755246 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTestWithMongoDB.java @@ -12,7 +12,7 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.eclipse.hawkbit.cache.TenantAwareCacheManager; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java index faf7649d0..293dcdf91 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ArtifactManagementTest.java @@ -32,8 +32,8 @@ import org.eclipse.hawkbit.repository.model.Artifact; import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider; import org.eclipse.hawkbit.repository.model.LocalArtifact; import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.util.HashGeneratorUtils; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.HashGeneratorUtils; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.slf4j.LoggerFactory; import org.springframework.data.mongodb.core.query.Criteria; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java index d26474bb4..b7da2ff06 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/DistributionSetManagementTest.java @@ -27,6 +27,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; +import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.Action; @@ -37,9 +38,15 @@ import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSe import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction; +import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; +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.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.fest.assertions.core.Condition; import org.junit.Test; import org.springframework.data.domain.Page; @@ -777,36 +784,55 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest { } @Test - @Description("Deltes a DS that is no in use. Expected behaviour is a soft delete on the database, i.e. only marked as " - + "deleted, kept eas refernce and unavailable for future use..") + @Description("Deletes a DS that is in use by either target assignment or rollout. Expected behaviour is a soft delete on the database, i.e. only marked as " + + "deleted, kept as reference but unavailable for future use..") public void deleteAssignedDistributionSet() { DistributionSet ds1 = testdataFactory.createDistributionSet("ds-1"); DistributionSet ds2 = testdataFactory.createDistributionSet("ds-2"); - DistributionSet dsAssigned = testdataFactory.createDistributionSet("ds-3"); + DistributionSet dsToTargetAssigned = testdataFactory.createDistributionSet("ds-3"); + final DistributionSet dsToRolloutAssigned = testdataFactory.createDistributionSet("ds-4"); ds1 = distributionSetManagement.findDistributionSetByNameAndVersion(ds1.getName(), ds1.getVersion()); ds2 = distributionSetManagement.findDistributionSetByNameAndVersion(ds2.getName(), ds2.getVersion()); // create assigned DS - dsAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsAssigned.getName(), - dsAssigned.getVersion()); + dsToTargetAssigned = distributionSetManagement.findDistributionSetByNameAndVersion(dsToTargetAssigned.getName(), + dsToTargetAssigned.getVersion()); final Target target = new JpaTarget("4712"); final Target savedTarget = targetManagement.createTarget(target); final List toAssign = new ArrayList<>(); toAssign.add(savedTarget); - deploymentManagement.assignDistributionSet(dsAssigned, toAssign); + deploymentManagement.assignDistributionSet(dsToTargetAssigned, toAssign); - // delete a ds - assertThat(distributionSetRepository.findAll()).hasSize(3); - distributionSetManagement.deleteDistributionSet(dsAssigned.getId()); + // create assigned rollout + createRolloutByVariables("test", "test", 5, "name==*", dsToRolloutAssigned, "50", "5"); + + // delete assigned ds + assertThat(distributionSetRepository.findAll()).hasSize(4); + distributionSetManagement.deleteDistributionSet(dsToTargetAssigned.getId(), dsToRolloutAssigned.getId()); // not assigned so not marked as deleted - assertThat(distributionSetRepository.findAll()).hasSize(3); + assertThat(distributionSetRepository.findAll()).hasSize(4); assertThat(distributionSetManagement .findDistributionSetsByDeletedAndOrCompleted(pageReq, Boolean.FALSE, Boolean.TRUE).getTotalElements()) .isEqualTo(2); } + private Rollout createRolloutByVariables(final String rolloutName, final String rolloutDescription, + final int groupSize, final String filterQuery, final DistributionSet distributionSet, + final String successCondition, final String errorCondition) { + final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder() + .successCondition(RolloutGroupSuccessCondition.THRESHOLD, successCondition) + .errorCondition(RolloutGroupErrorCondition.THRESHOLD, errorCondition) + .errorAction(RolloutGroupErrorAction.PAUSE, null).build(); + final Rollout rolloutToCreate = new JpaRollout(); + rolloutToCreate.setName(rolloutName); + rolloutToCreate.setDescription(rolloutDescription); + rolloutToCreate.setTargetFilterQuery(filterQuery); + rolloutToCreate.setDistributionSet(distributionSet); + return rolloutManagement.createRollout(rolloutToCreate, groupSize, conditions); + } + private Target sendUpdateActionStatusToTarget(final Status status, final Action updActA, final Target t, final String... msgs) { updActA.setStatus(status); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java index 4fba80616..ca82924a8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/ReportManagementTest.java @@ -37,9 +37,9 @@ import org.eclipse.hawkbit.repository.report.model.DataReportSeries; import org.eclipse.hawkbit.repository.report.model.DataReportSeriesItem; import org.eclipse.hawkbit.repository.report.model.InnerOuterDataReportSeries; import org.eclipse.hawkbit.repository.report.model.SeriesTime; -import org.eclipse.hawkbit.repository.util.TestdataFactory; -import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.After; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java index 42e5de498..381e9722d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java @@ -34,13 +34,13 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus; import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder; import org.eclipse.hawkbit.repository.model.RolloutGroupConditions; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; -import org.eclipse.hawkbit.repository.util.TestdataFactory; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Description; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java index 366dd6ec7..75633a85a 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SoftwareManagementTest.java @@ -39,7 +39,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java index e697f65d8..a89486757 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/SystemManagementTest.java @@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.report.model.TenantUsage; -import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; import org.junit.Test; import ru.yandex.qatools.allure.annotations.Description; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java index 79a7ad89f..4a83b1054 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TargetManagementTest.java @@ -38,13 +38,13 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag; import org.eclipse.hawkbit.repository.model.Action.Status; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Tag; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule; -import org.eclipse.hawkbit.repository.util.WithUser; import org.junit.Test; import org.springframework.data.domain.PageRequest; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java index 6604e3152..4eb15a78d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLDistributionSetFieldTest.java @@ -20,7 +20,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata; import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java index 47732dac2..25897ccde 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleFieldTest.java @@ -16,7 +16,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java index 3f843bffc..e04ee8c9b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleMetadataFieldsTest.java @@ -18,7 +18,7 @@ import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java index e1538aaee..344d0e320 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLSoftwareModuleTypeFieldsTest.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql; import static org.fest.assertions.api.Assertions.assertThat; +import org.eclipse.hawkbit.repository.Constants; import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; import org.eclipse.hawkbit.repository.model.SoftwareModuleType; @@ -34,7 +35,7 @@ public class RSQLSoftwareModuleTypeFieldsTest extends AbstractJpaIntegrationTest @Test @Description("Test filter software module test type by name") public void testFilterByParameterName() { - assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==Firmware", 1); + assertRSQLQuery(SoftwareModuleTypeFields.NAME.name() + "==" + Constants.SMT_DEFAULT_OS_NAME, 1); } @Test diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java index f21e4c938..2cccd655b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java @@ -24,7 +24,7 @@ import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.util.TestdataFactory; +import org.eclipse.hawkbit.repository.test.util.TestdataFactory; import org.junit.Before; import org.junit.Test; import org.springframework.data.domain.Page; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java index 86a0389d5..52f314171 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/tenancy/MultiTenancyEntityTest.java @@ -16,8 +16,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType; import org.eclipse.hawkbit.repository.jpa.model.JpaTarget; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.util.WithSpringAuthorityRule; -import org.eclipse.hawkbit.repository.util.WithUser; +import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule; +import org.eclipse.hawkbit.repository.test.util.WithUser; import org.junit.Test; import org.springframework.data.domain.Page; import org.springframework.data.domain.Slice; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java new file mode 100644 index 000000000..cb3f5476f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/matcher/BaseEntityMatcher.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.test.matcher; + +import org.eclipse.hawkbit.repository.model.BaseEntity; +import org.hamcrest.Factory; +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +/** + * Matcher for {@link BaseEntity}. + */ +public class BaseEntityMatcher { + + private BaseEntityMatcher() { + } + + @Factory + public static Matcher hasId(final Long id) { + return new HasIdMatcher(Matchers.equalTo(id)); + } + + private static class HasIdMatcher extends FeatureMatcher { + + public HasIdMatcher(final Matcher subMatcher) { + super(subMatcher, "getId()", "id"); + } + + @Override + protected Long featureValueOf(final BaseEntity baseEntity) { + return baseEntity.getId(); + } + } + +} diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java similarity index 99% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTest.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index c2bd61676..3d09fabc3 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter; import org.eclipse.hawkbit.repository.ArtifactManagement; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTestWithMongoDB.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java similarity index 98% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTestWithMongoDB.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java index 28d8add3a..bb54f550c 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/AbstractIntegrationTestWithMongoDB.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTestWithMongoDB.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.io.IOException; import java.net.UnknownHostException; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/CIMySqlTestDatabase.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java similarity index 98% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/CIMySqlTestDatabase.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java index e6bbe1f6a..3601f896e 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/CIMySqlTestDatabase.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/CIMySqlTestDatabase.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.sql.Connection; import java.sql.DriverManager; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/FreePortFileWriter.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java similarity index 97% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/FreePortFileWriter.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java index 383722a75..149cdf2b5 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/FreePortFileWriter.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/FreePortFileWriter.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.io.File; import java.net.InetSocketAddress; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/HashGeneratorUtils.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java similarity index 97% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/HashGeneratorUtils.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java index e222007f1..9d1dbca7c 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/HashGeneratorUtils.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/HashGeneratorUtils.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/JpaTestRepositoryManagement.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java similarity index 97% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/JpaTestRepositoryManagement.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java index 7ec5bb407..eae0b9a7d 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/JpaTestRepositoryManagement.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/JpaTestRepositoryManagement.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.util.List; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java similarity index 98% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestConfiguration.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java index acbaae2b4..e6a8e7686 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestConfiguration.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.util.concurrent.Executor; import java.util.concurrent.Executors; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestRepositoryManagement.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java similarity index 91% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestRepositoryManagement.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java index ddad59990..482c7725c 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestRepositoryManagement.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestRepositoryManagement.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; /** * Repository support for tests. diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestdataFactory.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java similarity index 99% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestdataFactory.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java index 1ed5679c8..81e2c1daf 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/TestdataFactory.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/TestdataFactory.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.io.InputStream; import java.nio.charset.Charset; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/Testdatabase.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java similarity index 90% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/Testdatabase.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java index b24d34533..e6f9be49f 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/Testdatabase.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/Testdatabase.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; /** * diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithSpringAuthorityRule.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java similarity index 99% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithSpringAuthorityRule.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java index b456cc32b..8f5f8e94b 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithSpringAuthorityRule.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithSpringAuthorityRule.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.lang.annotation.Annotation; import java.lang.reflect.Field; diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithUser.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java similarity index 97% rename from hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithUser.java rename to hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java index 04af9196b..a6151ed4c 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/util/WithUser.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/WithUser.java @@ -6,7 +6,7 @@ * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ -package org.eclipse.hawkbit.repository.util; +package org.eclipse.hawkbit.repository.test.util; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; diff --git a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java index 14ba8556e..1708bf6cc 100644 --- a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTest.java @@ -8,7 +8,7 @@ */ package org.eclipse.hawkbit.rest; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTest; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; import org.eclipse.hawkbit.rest.configuration.RestConfiguration; import org.eclipse.hawkbit.rest.util.FilterHttpResponse; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java index 4d952434d..70d65e141 100644 --- a/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java +++ b/hawkbit-rest-core/src/test/java/org/eclipse/hawkbit/rest/AbstractRestIntegrationTestWithMongoDB.java @@ -8,7 +8,7 @@ */ package org.eclipse.hawkbit.rest; -import org.eclipse.hawkbit.repository.util.AbstractIntegrationTestWithMongoDB; +import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTestWithMongoDB; import org.eclipse.hawkbit.rest.configuration.RestConfiguration; import org.eclipse.hawkbit.rest.util.FilterHttpResponse; import org.springframework.beans.factory.annotation.Autowired; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java index bad24e6c4..2cbadd02d 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionService.java @@ -17,7 +17,7 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; /** - * + * Service to check permissions. * */ public class PermissionService { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java new file mode 100644 index 000000000..ae8b604bb --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/PermissionUtils.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.im.authentication; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +/** + * Utility method for creation of GrantedAuthority collections etc. + */ +public final class PermissionUtils { + + private PermissionUtils() { + + } + + /** + * Create {@link GrantedAuthority} by a special role. + * + * @param roles + * the roles + * @return a list of {@link GrantedAuthority} + */ + public static List createAuthorityList(final Collection roles) { + final List authorities = new ArrayList<>(roles.size()); + + for (final String role : roles) { + authorities.add(new SimpleGrantedAuthority(role)); + } + + return authorities; + } + + /** + * Returns all authorities. + * + * @return a list of {@link GrantedAuthority} + */ + public static List createAllAuthorityList() { + return createAuthorityList(SpPermission.getAllAuthorities()); + } +} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java index bcd44e510..ce6bc7c40 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java @@ -9,7 +9,16 @@ package org.eclipse.hawkbit.im.authentication; import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.GrantedAuthority; @@ -35,6 +44,8 @@ import org.springframework.security.core.GrantedAuthority; */ public final class SpPermission { + private static final Logger LOGGER = LoggerFactory.getLogger(SpPermission.class); + /** * Permission to read the targets from the * {@link ProvisioningTargetRepository} including their meta information, @@ -139,6 +150,53 @@ public final class SpPermission { // Constants only } + /** + * Return all permission. + * + * @return all permission + */ + public static Collection getAllAuthorities() { + return getAllAuthorities(Collections.emptyList()); + } + + /** + * Return all permission. + * + * @param exclusionRoles + * roles which will excluded + * @return all permissions + */ + public static Collection getAllAuthorities(final String... exclusionRoles) { + return getAllAuthorities(Arrays.asList(exclusionRoles)); + } + + /** + * Return all permission. + * + * @param exclusionRoles + * roles which will excluded + * @return all permissions + */ + public static Collection getAllAuthorities(final Collection exclusionRoles) { + final List allPermissions = new ArrayList<>(); + final Field[] declaredFields = SpPermission.class.getDeclaredFields(); + for (final Field field : declaredFields) { + if (Modifier.isPublic(field.getModifiers()) && Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + try { + final String role = (String) field.get(null); + if (!(exclusionRoles.contains(role))) { + allPermissions.add(role); + } + } catch (final IllegalAccessException e) { + LOGGER.error(e.getMessage(), e); + } + + } + } + return allPermissions; + } + /** * Contains all the spring security evaluation expressions for the * {@link PreAuthorize} annotation for method security. diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java index f0d8f7d48..008aa3e95 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/DosFilter.java @@ -8,8 +8,10 @@ */ package org.eclipse.hawkbit.security; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.eclipse.hawkbit.security.SecurityConstants.SECURITY_LOG_PREFIX; + import java.io.IOException; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -31,25 +33,21 @@ import com.google.common.cache.CacheBuilder; /** * Filter for protection against denial of service attacks. It reduces the * maximum number of request per seconds which can be separately configured for - * read (GET) and write (PUT/POST/DELETE) requests. requests - * - * - * - * + * read (GET) and write (PUT/POST/DELETE) requests. */ public class DosFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DosFilter.class); - private static final Logger LOG_DOS = LoggerFactory.getLogger("server-security.dos"); - private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger("server-security.blacklist"); + private static final Logger LOG_DOS = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".dos"); + private static final Logger LOG_BLACKLIST = LoggerFactory.getLogger(SECURITY_LOG_PREFIX + ".blacklist"); private final Pattern ipAdressBlacklist; - private final Cache readCountCache = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.SECONDS).build(); + private final Cache readCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS) + .build(); - private final Cache writeCountCache = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.SECONDS).build(); + private final Cache writeCountCache = CacheBuilder.newBuilder().expireAfterAccess(1, SECONDS) + .build(); private final Integer maxRead; private final Integer maxWrite; @@ -78,7 +76,7 @@ public class DosFilter extends OncePerRequestFilter { */ public DosFilter(final Integer maxRead, final Integer maxWrite, final String ipDosWhiteListPattern, final String ipBlackListPattern, final String forwardHeader) { - super(); + this.maxRead = maxRead; this.maxWrite = maxWrite; this.forwardHeader = forwardHeader; @@ -96,21 +94,13 @@ public class DosFilter extends OncePerRequestFilter { } } - /* - * (non-Javadoc) - * - * @see - * org.springframework.web.filter.OncePerRequestFilter#doFilterInternal( - * javax.servlet.http. HttpServletRequest, - * javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) - */ @Override protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException { boolean processChain; - final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader).getHost(); + final String ip = IpUtil.getClientIpFromRequest(request, forwardHeader, true).getHost(); if (checkIpFails(ip)) { processChain = handleMissingIpAddress(response); } else { @@ -152,11 +142,9 @@ public class DosFilter extends OncePerRequestFilter { } private static boolean handleMissingIpAddress(final HttpServletResponse response) { - boolean processChain; LOG.error("Failed to get peer IP adress"); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); - processChain = false; - return processChain; + return false; } private boolean handleWriteRequest(final HttpServletResponse response, final String ip) { diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java index 6192a8f31..3f0be994a 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/HawkbitSecurityProperties.java @@ -82,10 +82,16 @@ public class HawkbitSecurityProperties { private String blacklist = ""; /** - * Name of the http header from which the remote ip is extracted. + * Name of the http header from which the remote ip is extracted for DDI + * connected clients. */ private String remoteIpHeader = "X-Forwarded-For"; + /** + * Set to true if DDI clients remote IP should be stored. + */ + private boolean trackRemoteIp = true; + public String getBlacklist() { return blacklist; } @@ -101,6 +107,14 @@ public class HawkbitSecurityProperties { public void setRemoteIpHeader(final String remoteIpHeader) { this.remoteIpHeader = remoteIpHeader; } + + public boolean isTrackRemoteIp() { + return trackRemoteIp; + } + + public void setTrackRemoteIp(final boolean trackRemoteIp) { + this.trackRemoteIp = trackRemoteIp; + } } /** diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java new file mode 100644 index 000000000..7285404a8 --- /dev/null +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityConstants.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.security; + +/** + * Constants related to security. + */ +public final class SecurityConstants { + + /** + * Logger prefix used for security logging. + */ + public static final String SECURITY_LOG_PREFIX = "server-security"; + + private SecurityConstants() { + + } +} diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java index 2d225c1dc..472e32493 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java @@ -14,12 +14,8 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; /** - * Auditor class that allows {@link BaseEntity}s to insert currenlt logged in - * user for repository changes. - * - * - * - * + * Auditor class that allows BaseEntitys to insert current logged in user for + * repository changes. * */ public class SpringSecurityAuditorAware implements AuditorAware { @@ -29,16 +25,21 @@ public class SpringSecurityAuditorAware implements AuditorAware { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || !authentication.isAuthenticated()) { + if (isAuthenticationInvalid(authentication)) { return null; } - if (authentication.getPrincipal() != null) { - if (authentication.getPrincipal() instanceof UserDetails) { - return ((UserDetails) authentication.getPrincipal()).getUsername(); - } - return authentication.getPrincipal().toString(); + return getCurrentAuditor(authentication); + } + + private String getCurrentAuditor(final Authentication authentication) { + if (authentication.getPrincipal() instanceof UserDetails) { + return ((UserDetails) authentication.getPrincipal()).getUsername(); } - return null; + return authentication.getPrincipal().toString(); + } + + private static boolean isAuthenticationInvalid(final Authentication authentication) { + return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null; } } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java index 4e08d8bfe..96fc557aa 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/util/IpUtil.java @@ -15,6 +15,8 @@ import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; +import org.eclipse.hawkbit.security.HawkbitSecurityProperties; + import com.google.common.net.HttpHeaders; /** @@ -45,17 +47,49 @@ public final class IpUtil { * @param request * the {@link HttpServletRequest} to determine the IP address * where this request has been sent from - * @param forwardHeader - * the header name containing the IP address e.g. forwarded by a - * proxy {@code x-forwarded-for} + * @param securityProperties + * hawkBit security properties. * @return the {@link URI} based IP address from the client which sent the * request */ - public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader) { - String ip = request.getHeader(forwardHeader); - if (ip == null || (ip = findClientIpAddress(ip)) == null) { - ip = request.getRemoteAddr(); + public static URI getClientIpFromRequest(final HttpServletRequest request, + final HawkbitSecurityProperties securityProperties) { + + return getClientIpFromRequest(request, securityProperties.getClients().getRemoteIpHeader(), + securityProperties.getClients().isTrackRemoteIp()); + } + + /** + * Retrieves the string based IP address from a given + * {@link HttpServletRequest} by either the + * {@link HttpHeaders#X_FORWARDED_FOR} or by the + * {@link HttpServletRequest#getRemoteAddr()} methods. + * + * @param request + * the {@link HttpServletRequest} to determine the IP address + * where this request has been sent from + * @param forwardHeader + * the header name containing the IP address e.g. forwarded by a + * proxy {@code x-forwarded-for} + * + * @param trackRemoteIp + * to true if remote IP should be tracked. + * @return the {@link URI} based IP address from the client which sent the + * request + */ + public static URI getClientIpFromRequest(final HttpServletRequest request, final String forwardHeader, + final boolean trackRemoteIp) { + String ip; + + if (trackRemoteIp) { + ip = request.getHeader(forwardHeader); + if (ip == null || (ip = findClientIpAddress(ip)) == null) { + ip = request.getRemoteAddr(); + } + } else { + ip = "***"; } + return createHttpUri(ip); } diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java new file mode 100644 index 000000000..bca7fd1c1 --- /dev/null +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/im/authentication/PermissionTest.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.im.authentication; + +import static org.fest.assertions.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; +import org.springframework.context.annotation.Description; +import org.springframework.security.core.GrantedAuthority; + +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +/** + * Test {@link SpPermission}. + */ +@Features("Unit Tests - Security") +@Stories("Permission Test") +public final class PermissionTest { + + @Test + @Description("Verify the get permission function") + public void testGetPermissions() { + final int allPermission = 15; + final int permissionWithoutSystem = allPermission - 3; + final Collection allAuthorities = SpPermission.getAllAuthorities(); + final List allAuthoritiesList = PermissionUtils.createAllAuthorityList(); + assertThat(allAuthorities).hasSize(allPermission); + assertThat(allAuthoritiesList).hasSize(allPermission); + assertThat(allAuthoritiesList.stream().map(authority -> authority.getAuthority()).collect(Collectors.toList())) + .containsAll(allAuthorities); + + final Collection authoritiesWithoutSystem = SpPermission.getAllAuthorities(SpPermission.SYSTEM_ADMIN, + SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR); + final List authoritiesListWithoutSystem = PermissionUtils.createAuthorityList(SpPermission + .getAllAuthorities(SpPermission.SYSTEM_ADMIN, SpPermission.SYSTEM_DIAG, SpPermission.SYSTEM_MONITOR)); + + assertThat(authoritiesWithoutSystem).hasSize(permissionWithoutSystem); + assertThat(authoritiesListWithoutSystem).hasSize(permissionWithoutSystem); + assertThat(authoritiesListWithoutSystem.stream().map(authority -> authority.getAuthority()) + .collect(Collectors.toList())).containsAll(authoritiesWithoutSystem); + + } +} diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java index 9eb83d2a9..0f4a01d26 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/util/IpUtilTest.java @@ -50,7 +50,7 @@ public class IpUtilTest { when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost()); // test - final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux"); + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", true); // verify assertThat(remoteAddr).as("The remote address should be as the known client IP address") @@ -59,6 +59,25 @@ public class IpUtilTest { verify(requestMock, times(1)).getRemoteAddr(); } + @Test + @Description("Tests create uri from request with masked IP when IP tracking is disabled") + public void maskRemoteAddrIfDisabled() { + // known values + final URI knownRemoteClientIP = IpUtil.createHttpUri("***"); + // mock + when(requestMock.getHeader(HttpHeaders.X_FORWARDED_FOR)).thenReturn(null); + when(requestMock.getRemoteAddr()).thenReturn(knownRemoteClientIP.getHost()); + + // test + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "bumlux", false); + + // verify + assertThat(remoteAddr).as("The remote address should be as the known client IP address") + .isEqualTo(knownRemoteClientIP); + verify(requestMock, times(0)).getHeader("bumlux"); + verify(requestMock, times(0)).getRemoteAddr(); + } + @Test @Description("Tests create uri from x forward header") public void getRemoteAddrFromXForwardedForHeader() { @@ -69,7 +88,7 @@ public class IpUtilTest { when(requestMock.getRemoteAddr()).thenReturn(null); // test - final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For"); + final URI remoteAddr = IpUtil.getClientIpFromRequest(requestMock, "X-Forwarded-For", true); // verify assertThat(remoteAddr).as("The remote address should be as the known client IP address") diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java index 7fe8e25de..a9baad65b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java @@ -208,6 +208,7 @@ public class SoftwareModuleAddUpdateWindow extends CustomComponent implements Se * (controller Id, name & description) and action buttons layout */ addStyleName("lay-color"); + setSizeUndefined(); formLayout = new FormLayout(); formLayout.setCaption(null); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java index c8a0c650e..8578ad2a4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateUpdateSoftwareTypeLayout.java @@ -330,6 +330,8 @@ public class CreateUpdateSoftwareTypeLayout extends CreateUpdateTypeLayout getColorPickerLayout().getSelPreview().setColor(getColorPickerLayout().getSelectedColor()); mainLayout.addComponent(colorPickerLayout, 1, 0); mainLayout.setComponentAlignment(colorPickerLayout, Alignment.MIDDLE_CENTER); + } else { + mainLayout.removeComponent(colorPickerLayout); } tagPreviewBtnClicked = !tagPreviewBtnClicked; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java index 5399e59c8..ed2feef0a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java @@ -53,70 +53,65 @@ public class ArtifactUploadState implements ManagmentEntityState, Serializ private Set selectedSoftwareModules = Collections.emptySet(); - private boolean swTypeFilterClosed = Boolean.FALSE; + private boolean swTypeFilterClosed; - private boolean swModuleTableMaximized = Boolean.FALSE; + private boolean swModuleTableMaximized; - private boolean artifactDetailsMaximized = Boolean.FALSE; + private boolean artifactDetailsMaximized; private final Set selectedDeleteSWModuleTypes = new HashSet<>(); - private boolean noDataAvilableSoftwareModule = Boolean.FALSE; - - private boolean isStatusPopupMinimized = Boolean.FALSE; - - private boolean isUploadCompleted = Boolean.FALSE; - + private boolean noDataAvilableSoftwareModule; + + private boolean statusPopupMinimized; + + private boolean uploadCompleted; + private List uploadedFileStatusList = new ArrayList<>(); - + private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger(); private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger(); - + private final AtomicInteger numberOfFileUploadsFailed = new AtomicInteger(); public AtomicInteger getNumberOfFileUploadsFailed() { return numberOfFileUploadsFailed; } - + public AtomicInteger getNumberOfFilesActuallyUpload() { return numberOfFilesActuallyUpload; } - + public AtomicInteger getNumberOfFileUploadsExpected() { return numberOfFileUploadsExpected; } - - + public List getUploadedFileStatusList() { return uploadedFileStatusList; } - - public void setUploadedFileStatusList(List uploadedFileStatusList) { + + public void setUploadedFileStatusList(final List uploadedFileStatusList) { this.uploadedFileStatusList = uploadedFileStatusList; } - + public boolean isUploadCompleted() { - return isUploadCompleted; - } - - public void setUploadCompleted(boolean isUploadCompleted) { - this.isUploadCompleted = isUploadCompleted; + return uploadCompleted; + } + + public void setUploadCompleted(final boolean uploadCompleted) { + this.uploadCompleted = uploadCompleted; + } + + public void setStatusPopupMinimized(final boolean statusPopupMinimized) { + this.statusPopupMinimized = statusPopupMinimized; } - - public void setStatusPopupMinimized(boolean isStatusPopupMinimized) { - this.isStatusPopupMinimized = isStatusPopupMinimized; - } - public boolean isStatusPopupMinimized() { - return isStatusPopupMinimized; - } + return statusPopupMinimized; + } - - - - /** + /** * Set software. * * @return diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java index 584d89ace..eec189eaf 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadStatusObject.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.ui.artifacts.upload; +import java.io.Serializable; + import org.eclipse.hawkbit.repository.model.SoftwareModule; /** @@ -16,22 +18,24 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; * popup. * */ -public class UploadStatusObject { +public class UploadStatusObject implements Serializable { + private static final long serialVersionUID = 1L; + private String status; private Double progress; private String filename; private String reason; - private SoftwareModule selectedSoftwareModule; + private final SoftwareModule selectedSoftwareModule; public UploadStatusObject(final String status, final Double progress, final String fileName, final String reason, final SoftwareModule selectedSoftwareModule) { - this(fileName,selectedSoftwareModule); + this(fileName, selectedSoftwareModule); this.status = status; this.progress = progress; this.reason = reason; } - public UploadStatusObject(String fileName, SoftwareModule selectedSoftwareModule) { + public UploadStatusObject(final String fileName, final SoftwareModule selectedSoftwareModule) { this.filename = fileName; this.selectedSoftwareModule = selectedSoftwareModule; } @@ -44,7 +48,7 @@ public class UploadStatusObject { return status; } - public void setStatus(String status) { + public void setStatus(final String status) { this.status = status; } @@ -52,7 +56,7 @@ public class UploadStatusObject { return progress; } - public void setProgress(Double progress) { + public void setProgress(final Double progress) { this.progress = progress; } @@ -60,7 +64,7 @@ public class UploadStatusObject { return filename; } - public void setFilename(String filename) { + public void setFilename(final String filename) { this.filename = filename; } @@ -68,19 +72,38 @@ public class UploadStatusObject { return reason; } - public void setReason(String reason) { + public void setReason(final String reason) { this.reason = reason; } @Override - public boolean equals(Object obj) { - if (this == null || obj == null) { - return false; - } - if (obj instanceof UploadStatusObject && this.getFilename() == ((UploadStatusObject) obj).getFilename()) { + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((filename == null) ? 0 : filename.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { return true; } - return false; + if (obj == null) { + return false; + } + if (!(obj instanceof UploadStatusObject)) { + return false; + } + final UploadStatusObject other = (UploadStatusObject) obj; + if (filename == null) { + if (other.filename != null) { + return false; + } + } else if (!filename.equals(other.filename)) { + return false; + } + return true; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java index 7818953b0..80d3de078 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java @@ -36,6 +36,7 @@ import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; 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; @@ -187,6 +188,9 @@ public class CommonDialogWindow extends Window implements Serializable { ((AbstractOrderedLayout) content).setSpacing(true); ((AbstractOrderedLayout) content).setMargin(true); } + if (content instanceof GridLayout) { + addStyleName(""); + } if (null != content) { mainLayout.addComponent(content); 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 8fb5a8b42..d9a964b04 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 @@ -175,11 +175,7 @@ public final class UserDetailsFormatter { private static UserDetails loadUserByUsername(final String username) { final UserDetailsService userDetailsService = SpringContextHelper.getBean(UserDetailsService.class); try { - final UserDetails loadUserByUsername = userDetailsService.loadUserByUsername(username); - if (loadUserByUsername == null) { - throw new UsernameNotFoundException("User not found " + username); - } - return loadUserByUsername; + return userDetailsService.loadUserByUsername(username); } catch (final UsernameNotFoundException e) { return new User(username, "", Collections.emptyList()); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java index 09d79572c..cc48b47db 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterButtons.java @@ -155,6 +155,7 @@ public abstract class AbstractFilterButtons extends Table { columnIds.add(FILTER_BUTTON_COLUMN); setVisibleColumns(columnIds.toArray()); setColumnHeaderMode(ColumnHeaderMode.HIDDEN); + setColumnWidth(FILTER_BUTTON_COLUMN, 137); } private Button createFilterButton(final Long id, final String name, final String description, final String color, @@ -179,6 +180,7 @@ public abstract class AbstractFilterButtons extends Table { button.setDescription(name); } button.setData(id == null ? SPUIDefinitions.NO_TAG_BUTTON_ID : itemId); + return button; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/decorators/SPUITagButtonStyle.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/decorators/SPUITagButtonStyle.java index 014bdbfb9..a95317d8a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/decorators/SPUITagButtonStyle.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/decorators/SPUITagButtonStyle.java @@ -8,8 +8,6 @@ */ package org.eclipse.hawkbit.ui.decorators; -import org.eclipse.hawkbit.ui.utils.SPUIButtonDefinitions; - import com.vaadin.server.Resource; import com.vaadin.ui.Button; import com.vaadin.ui.themes.ValoTheme; @@ -22,16 +20,10 @@ public class SPUITagButtonStyle implements SPUIButtonDecorator { @Override public Button decorate(final Button button, final String style, final boolean setStyle, final Resource icon) { - /** - * Add ... for long name - */ - final String buttonCaption = button.getCaption(); - if (buttonCaption != null && buttonCaption.length() > SPUIButtonDefinitions.BUTTON_CAPTION_LENGTH) { - button.setCaption(buttonCaption.substring(0, SPUIButtonDefinitions.BUTTON_CAPTION_LENGTH) + "..."); - } button.setImmediate(true); - button.addStyleName("button-no-border" + " " + ValoTheme.BUTTON_BORDERLESS + " " + ValoTheme.BUTTON_TINY + " " + button.addStyleName("generatedColumnPadding button-no-border" + " " + ValoTheme.BUTTON_BORDERLESS + " " + "button-tag-no-border"); + // Set Style if (null != style) { if (setStyle) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateUpdateDistSetTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateUpdateDistSetTypeLayout.java index facf6e008..4d5579de0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateUpdateDistSetTypeLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateUpdateDistSetTypeLayout.java @@ -717,6 +717,8 @@ public class CreateUpdateDistSetTypeLayout extends CreateUpdateTypeLayout getColorPickerLayout().getSelPreview().setColor(getColorPickerLayout().getSelectedColor()); mainLayout.addComponent(colorPickerLayout, 1, 0); mainLayout.setComponentAlignment(colorPickerLayout, Alignment.MIDDLE_CENTER); + } else { + mainLayout.removeComponent(colorPickerLayout); } tagPreviewBtnClicked = !tagPreviewBtnClicked; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractCreateUpdateTagLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractCreateUpdateTagLayout.java index a6fc1accb..720f61cff 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractCreateUpdateTagLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractCreateUpdateTagLayout.java @@ -198,6 +198,7 @@ public abstract class AbstractCreateUpdateTagLayout extends CustomComponent i18n.get("label.combobox.tag")); tagNameComboBox.addStyleName(SPUIDefinitions.FILTER_TYPE_COMBO_STYLE); tagNameComboBox.setImmediate(true); + tagNameComboBox.setId(SPUIComponentIdProvider.DIST_TAG_COMBO); tagColorPreviewBtn = new Button(); tagColorPreviewBtn.setId(SPUIComponentIdProvider.TAG_COLOR_PREVIEW_ID); @@ -266,6 +267,8 @@ public abstract class AbstractCreateUpdateTagLayout extends CustomComponent mainLayout.getComponent(1, 0); mainLayout.addComponent(colorPickerLayout, 1, 0); mainLayout.setComponentAlignment(colorPickerLayout, Alignment.MIDDLE_CENTER); + } else { + mainLayout.removeComponent(colorPickerLayout); } tagPreviewBtnClicked = !tagPreviewBtnClicked; } @@ -478,6 +481,7 @@ public abstract class AbstractCreateUpdateTagLayout extends CustomComponent protected void createOptionGroup(final boolean hasCreatePermission, final boolean hasUpdatePermission) { optiongroup = new OptionGroup("Select Action"); + optiongroup.setId(SPUIComponentIdProvider.OPTION_GROUP); optiongroup.addStyleName(ValoTheme.OPTIONGROUP_SMALL); optiongroup.addStyleName("custom-option-group"); optiongroup.setNullSelectionAllowed(false); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java index d6a613cf7..982e9d75b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java @@ -98,7 +98,7 @@ public class BulkUploadHandler extends CustomComponent final TargetBulkUpdateWindowLayout targetBulkUpdateWindowLayout; - private final EntityFactory entityFactory; + private transient EntityFactory entityFactory; /** * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java index 287df14b3..5913bc9d1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java @@ -129,13 +129,13 @@ public class TargetAddUpdateWindowLayout extends CustomComponent { * The main layout of the window contains mandatory info, textboxes * (controller Id, name & description) and action buttons layout */ - + setSizeUndefined(); formLayout = new FormLayout(); formLayout.addComponent(controllerIDTextField); formLayout.addComponent(nameTextField); formLayout.addComponent(descTextArea); - nameTextField.focus(); + controllerIDTextField.focus(); } private void addListeners() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java index 9757df522..496bb5cb4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIComponentIdProvider.java @@ -176,6 +176,10 @@ public final class SPUIComponentIdProvider { * ID - Dist jvm combo. */ public static final String DIST_MODULE_COMBO = "dist.module.combo."; + /** + * ID for Distribution Tag ComboBox + */ + public static final String DIST_TAG_COMBO = "dist.tag.combo"; /** * ID-Dist.PIN. */ @@ -302,11 +306,14 @@ public final class SPUIComponentIdProvider { * tag color preview button id. */ public static final String TAG_COLOR_PREVIEW_ID = "tag.color.preview"; - /** * Id for ColorPickerLayout */ public static final String COLOR_PICKER_LAYOUT = "color.picker.layout"; + /** + * Id for OptionGroup Create/Update tag + */ + public static final String OPTION_GROUP = "create.update.tag"; /** * Confirmation dialogue OK button id. */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java index 1a6e8c163..e955c9f97 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java @@ -344,15 +344,6 @@ public final class SPUIDefinitions { * New Target tag color lable id. */ public static final String NEW_TARGET_TAG_COLOR = "target.tag.add.color"; - /** - * New Target tag save icon id. - */ - // public static final String NEW_TARGET_TAG_SAVE = "target.tag.add.save"; - /** - * New Target tag discard icon id. - */ - // public static final String NEW_TARGET_TAG_DISRACD = - // "target.tag.add.discard"; /** * New Target tag add icon id. */ diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/table-common.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/table-common.scss index 8820dbcc9..3bfc12aac 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/table-common.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/table-common.scss @@ -181,4 +181,13 @@ visibility: hidden; float: right; } + + .v-button-generatedColumnPadding { + height: 28px; + padding: 0 6px !important; + font-size: 12px; + border-radius: 4px; + } + + } diff --git a/pom.xml b/pom.xml index 33ad1f81e..f50afa0ab 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,6 @@ examples - ${release.scm.connection} ${release.scm.developerConnection} @@ -69,6 +68,8 @@ 2.5.5 5.2.4.Final 1.2.0.RELEASE + 1.6.0.RELEASE + 0.18.0.RELEASE Fowler-SR1 3.2.2 @@ -86,6 +87,10 @@ 4.5 + 3.1.0 + 2.17 + 1.9.4 + 1.1.0.Final 1.4 @@ -152,6 +157,15 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + -Xlint:all + true + true + + com.mycila license-maven-plugin @@ -182,7 +196,7 @@ maven-scm-plugin - 1.9.4 + ${maven.scm.plugin.version} ${project.version} @@ -190,7 +204,6 @@ org.jacoco jacoco-maven-plugin - ${jacoco.version} prepare-ut-agent @@ -231,6 +244,7 @@ + @@ -274,7 +288,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.17 + ${maven.surefire.plugin.version} true 1 @@ -348,9 +362,13 @@ org.jacoco jacoco-maven-plugin - ${jacoco.maven.version} + ${jacoco.version} + + + org.bsc.maven + maven-processor-plugin + ${maven.processor.plugin.version} -