Feature horizontal scalability (#305)

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Dennis Melzer
2016-11-03 15:53:53 +01:00
committed by Kai Zimmermann
parent 07cb62a3dd
commit 866bc72114
287 changed files with 4219 additions and 5046 deletions

View File

@@ -63,7 +63,6 @@ $ java -jar ./examples/hawkbit-example-mgmt-simulator/target/hawkbit-example-mgm
* `examples` : hawkBit examples
* `hawkbit-artifact-repository-mongo` : Artifact repository implementation to mongoDB.
* `hawkbit-autoconfigure` : Spring-boot auto-configuration.
* `hawkbit-cache-redis` : Spring cache manager configuration and implementation with redis, distributed cache and distributed events.
* `hawkbit-core` : Core elements for internal interfaces and utility classes.
* `hawkbit-ddi-api` : The hawkBit DDI API.
* `hawkbit-ddi-dl-api` : The hawkBit DDI Download API.

View File

@@ -9,4 +9,3 @@ Example projects that show how _hawkBit_ can be used to create, run or access an
- `hawkbit-example-ddi-feign-client` : Example _hawkBit_ DDI client based on the _hawkBit_ DDI API.
- `hawkbit-example-mgmt-feign-client` : Example _hawkBit_ Management client based on the _hawkBit_ Management API
- `hawkbit-example-mgmt-simulator` : Example client simulation for the _hawkBit_ Management API based on Spring Boot and the hawkbit-example-mgmt-feign-client.

View File

@@ -93,16 +93,6 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>

View File

@@ -8,14 +8,10 @@ package org.eclipse.hawkbit.app;
* http://www.eclipse.org/legal/epl-v10.html
*/
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.vaadin.spring.events.EventBus.SessionEventBus;
import com.google.common.eventbus.EventBus;
import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
@@ -39,9 +35,15 @@ public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
public MyUI(final ScheduledExecutorService executorService, final EventBus systemEventBus,
final org.vaadin.spring.events.EventBus.SessionEventBus eventBus, final UIEventProvider provider) {
super(new DelayedEventBusPushStrategy(executorService, eventBus, systemEventBus, provider));
/**
* Constructor
*
* @param pushStrategy
* the push strategy
* @param eventBus
* the event bus
*/
public MyUI(final EventPushStrategy pushStrategy, final SessionEventBus eventBus) {
super(pushStrategy, eventBus);
}
}

View File

@@ -105,11 +105,11 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>

View File

@@ -12,9 +12,6 @@ import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event description which indicates the initialization of an update.
*
* @author Michael Hirsch
*
*/
public class InitUpdate {

View File

@@ -13,10 +13,7 @@ import java.util.Collection;
import org.eclipse.hawkbit.simulator.AbstractSimulatedDevice;
/**
* Event description which indicates an poll time update.
*
* @author Michael Hirsch
*
* Event description which indicates a poll time update.
*/
public class NextPollCounterUpdate {

View File

@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.simulator.DeviceSimulatorRepository;
import org.eclipse.hawkbit.simulator.SimulatedDeviceFactory;
import org.eclipse.hawkbit.simulator.UpdateStatus.ResponseStatus;
import org.eclipse.hawkbit.simulator.amqp.AmqpProperties;
import org.eclipse.hawkbit.simulator.amqp.SpSenderService;
import org.eclipse.hawkbit.simulator.event.InitUpdate;
import org.eclipse.hawkbit.simulator.event.NextPollCounterUpdate;
import org.eclipse.hawkbit.simulator.event.ProgressUpdate;
@@ -58,9 +57,6 @@ import com.vaadin.ui.renderers.ProgressBarRenderer;
@SuppressWarnings("squid:MaximumInheritanceDepth")
public class SimulatorView extends VerticalLayout implements View {
/**
*
*/
private static final String HTML_SPAN = ";</span>";
private static final String NEXT_POLL_COUNTER_SEC_COL = "nextPollCounterSec";
@@ -81,10 +77,9 @@ public class SimulatorView extends VerticalLayout implements View {
private static final long serialVersionUID = 1L;
@Autowired
private transient SpSenderService spSenderService;
@Autowired
private transient DeviceSimulatorRepository repository;
@Autowired
private transient SimulatedDeviceFactory deviceFactory;

View File

@@ -14,7 +14,6 @@ security.user.password=${BASIC_PASSWORD:admin}
security.user.role=USER
security.require-ssl=false
security.enable-csrf=false
security.basic.enabled=true
security.basic.realm=DeviceSimulator
security.basic.path= /**
security.basic.authorize-mode=ROLE

View File

@@ -12,16 +12,7 @@
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<Root level="INFO">
<Root level="ERROR">
<appender-ref ref="CONSOLE" />
</Root>

View File

@@ -33,3 +33,45 @@ The Management API can be accessed via http://localhost:8080/rest/v1
- **manifest-simple.yml** for a standalone hawkBit installation with embedded H2.
- **manifest.yml** for a standalone hawkBit installation with embedded H2 and RabbitMQ service binding for DMF integration (note: this manifest is used for the sandbox above).
- Run ```cf push``` against you cloud foundry environment.
# Enable Clustering (experimental)
Clustering in hawkBit is based on _Spring Cloud Bus_. It is not enabled in the example app by default.
Add to your `application.properties` :
```
spring.cloud.bus.enabled=true
```
Add to your `pom.xml` :
```
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
```
Optional as well is the addition of [Protostuff](https://github.com/protostuff/protostuff) based message payload serialization for improved performance.
Add to your `application.properties` :
```
spring.cloud.stream.bindings.springCloudBusInput.content-type=application/binary+protostuff
spring.cloud.stream.bindings.springCloudBusOutput.content-type=application/binary+protostuff
```
Add to your `pom.xml` :
```
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
</dependency>
```

View File

@@ -97,7 +97,6 @@
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -8,14 +8,10 @@
*/
package org.eclipse.hawkbit.app;
import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.vaadin.spring.events.EventBus.SessionEventBus;
import com.google.common.eventbus.EventBus;
import com.vaadin.annotations.Push;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
@@ -35,12 +31,18 @@ import com.vaadin.spring.annotation.SpringUI;
// Vaadin.
@SuppressWarnings({ "squid:MaximumInheritanceDepth" })
public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
public MyUI(final ScheduledExecutorService scheduledExecutorService, final EventBus systemEventBus,
final org.vaadin.spring.events.EventBus.SessionEventBus eventBus, final UIEventProvider provider) {
super(new DelayedEventBusPushStrategy(scheduledExecutorService, eventBus, systemEventBus, provider));
/**
* Constructor
*
* @param pushStrategy
* the push strategy
* @param eventBus
* the event bus
*/
public MyUI(final EventPushStrategy pushStrategy, final SessionEventBus eventBus) {
super(pushStrategy, eventBus);
}
}

View File

@@ -22,7 +22,7 @@
<dependencies>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
@@ -46,7 +46,7 @@
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-slf4j</artifactId>
</dependency>
</dependencies>

View File

@@ -41,11 +41,11 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>

View File

@@ -36,12 +36,11 @@
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<!-- need to overwrite for the interface inheritance feature of feign-core -->
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>
<dependency>

View File

@@ -42,22 +42,4 @@
<module>hawkbit-example-mgmt-feign-client</module>
<module>hawkbit-example-mgmt-simulator</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-jackson</artifactId>
<version>8.16.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -26,12 +26,6 @@
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-cache-redis</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-dmf-amqp</artifactId>
@@ -83,5 +77,15 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -8,17 +8,21 @@
*/
package org.eclipse.hawkbit.autoconfigure.cache;
import static com.google.common.cache.CacheBuilder.newBuilder;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.cache.TenancyCacheManager;
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
import org.eclipse.hawkbit.tenancy.TenantAware;
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.context.properties.EnableConfigurationProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
@@ -27,6 +31,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.google.common.cache.CacheBuilder;
/**
* A configuration for configuring the spring {@link CacheManager} for specific
* multi-tenancy caching. The caches between tenants must not interfere each
@@ -37,33 +43,58 @@ import org.springframework.context.annotation.Primary;
*/
@Configuration
@EnableCaching
public class CacheAutoConfiguration extends CachingConfigurerSupport {
public class CacheAutoConfiguration {
@Autowired
private TenantAware tenantAware;
@Autowired
@Qualifier("directCacheManager")
private CacheManager directCacheManager;
/**
* @return the default cache manager bean if none other cache manager is
* existing.
*/
@Override
@Bean
@ConditionalOnMissingBean
@Primary
public TenancyCacheManager cacheManager() {
return new TenantAwareCacheManager(directCacheManager(), tenantAware);
return new TenantAwareCacheManager(directCacheManager, tenantAware);
}
/**
* @return the direct cache manager to access without tenant aware check,
* cause in sometimes it's necessary to access the cache directly
* without having the current tenant, e.g. initial creation of
* tenant
* A separate configuration of the direct cache manager for the
* {@link TenantAwareCacheManager} that it can get overridden by another
* configuration.
*/
@Configuration
@EnableConfigurationProperties(CacheProperties.class)
static class DirectCacheManagerConfiguration {
@Autowired
private CacheProperties cacheProperties;
/**
* @return the direct cache manager to access without tenant aware
* check, cause in sometimes it's necessary to access the cache
* directly without having the current tenant, e.g. initial
* creation of tenant
*/
@Bean(name = "directCacheManager")
@ConditionalOnMissingBean(name = "directCacheManager")
public CacheManager directCacheManager() {
return new GuavaCacheManager();
final GuavaCacheManager cacheManager = new GuavaCacheManager();
if (cacheProperties.getTtl() > 0) {
final CacheBuilder<Object, Object> cacheBuilder = newBuilder()
.expireAfterWrite(cacheProperties.getTtl(), cacheProperties.getTtlUnit());
cacheManager.setCacheBuilder(cacheBuilder);
}
return cacheManager;
}
}
/**
@@ -198,6 +229,11 @@ public class CacheAutoConfiguration extends CachingConfigurerSupport {
delegate.clear();
}
@Override
public <T> T get(final Object key, final Callable<T> valueLoader) {
return delegate.get(key, valueLoader);
}
}
}

View File

@@ -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.autoconfigure.cache;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for configuring the cache within a cluster. The TTL (time to live)
* is used for the lifetime limit of data in caches. After lifetime the data
* gets reloaded out of the database.
*/
@ConfigurationProperties("hawkbit.cache.global")
public class CacheProperties {
/**
* TTL for cached entries in millis.
*/
private int ttl;
/**
* Initial delay in millis
*/
private int initialDelay;
public long getInitialDelay() {
return initialDelay;
}
public void setInitialDelay(final int initialDelay) {
this.initialDelay = initialDelay;
}
public int getTtl() {
return ttl;
}
public void setTtl(final int ttl) {
this.ttl = ttl;
}
public final TimeUnit getTtlUnit() {
return MILLISECONDS;
}
}

View File

@@ -8,10 +8,10 @@
*/
package org.eclipse.hawkbit.autoconfigure.cache;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.TenancyCacheManager;
import org.eclipse.hawkbit.cache.DefaultDownloadIdCache;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -20,9 +20,6 @@ import org.springframework.context.annotation.Configuration;
* A configuration for configuring a cache for the download id's.
*
* This is done by providing a named cache.
*
*
*
*/
@Configuration
public class DownloadIdCacheAutoConfiguration {
@@ -31,16 +28,18 @@ public class DownloadIdCacheAutoConfiguration {
private CacheManager cacheManager;
/**
* Bean for the download id cache.
* Bean for the downloadId cache that returns the DefaultDownloadIdCache.
* The DefaultDownloadIdCache cannot be used within a cluster because the
* downloadId cache is not shared among notes. This means, a downloadId
* which is stored on note A for downloading an artifact can only be used
* for downloading the artifact form node A.
*
* @return the cache
* @return the DefaultDownloadIdCache
*/
@Bean(name = CacheConstants.DOWNLOAD_ID_CACHE)
public Cache downloadIdCache() {
if (cacheManager instanceof TenancyCacheManager) {
return ((TenancyCacheManager) cacheManager).getDirectCache(CacheConstants.DOWNLOAD_ID_CACHE);
}
return cacheManager.getCache(CacheConstants.DOWNLOAD_ID_CACHE);
@Bean
@ConditionalOnMissingBean
public DownloadIdCache downloadIdCache() {
return new DefaultDownloadIdCache(cacheManager);
}
}

View File

@@ -1,27 +0,0 @@
/**
* 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.cache;
import org.eclipse.hawkbit.cache.RedisConfiguration;
import org.eclipse.hawkbit.cache.annotation.EnableRedis;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
/**
* A configuration for configuring the redis configuration.
*
*
*
*/
@Configuration
@ConditionalOnClass(value = RedisConfiguration.class)
@EnableRedis
public class RedisAutoConfiguration {
}

View File

@@ -0,0 +1,131 @@
/**
* 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.event;
import java.util.concurrent.Executor;
import org.eclipse.hawkbit.event.BusProtoStuffMessageConverter;
import org.eclipse.hawkbit.repository.event.remote.RemoteTenantAwareEvent;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.bus.ConditionalOnBusEnabled;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.messaging.converter.MessageConverter;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
/**
* Auto configuration for the event bus.
*
*/
@Configuration
@RemoteApplicationEventScan(basePackages = "org.eclipse.hawkbit.repository.event.remote")
public class EventPublisherAutoConfiguration {
@Autowired
@Qualifier("asyncExecutor")
private Executor executor;
@Autowired
private TenantAware tenantAware;
/**
* Server internal event publisher that allows parallel event processing if
* the event listener is marked as so.
*
* @return publisher bean
*/
@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)
public ApplicationEventMulticaster applicationEventMulticaster() {
final SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new TenantAwareApplicationEventPublisher(
tenantAware);
simpleApplicationEventMulticaster.setTaskExecutor(executor);
return simpleApplicationEventMulticaster;
}
/**
* Bean for creating a singleton instance of the
* {@link EventPublisherHolder}
*
* @return the singleton instance of the {@link EventPublisherHolder}
*/
@Bean
public EventPublisherHolder eventBusHolder() {
return EventPublisherHolder.getInstance();
}
private static class TenantAwareApplicationEventPublisher extends SimpleApplicationEventMulticaster {
private final TenantAware tenantAware;
@Autowired(required = false)
private ServiceMatcher serviceMatcher;
/**
* Constructor.
*
* @param tenantAware
* the tenant ware
*/
protected TenantAwareApplicationEventPublisher(final TenantAware tenantAware) {
this.tenantAware = tenantAware;
}
/**
* Was overridden that not every event has to run within a own
* tenantAware.
*/
@Override
public void multicastEvent(final ApplicationEvent event, final ResolvableType eventType) {
if (serviceMatcher == null || !(event instanceof RemoteTenantAwareEvent)) {
super.multicastEvent(event, eventType);
return;
}
final RemoteTenantAwareEvent remoteEvent = (RemoteTenantAwareEvent) event;
if (serviceMatcher.isFromSelf(remoteEvent)) {
super.multicastEvent(event, eventType);
return;
}
tenantAware.runAsTenant(remoteEvent.getTenant(), () -> {
super.multicastEvent(event, eventType);
return null;
});
}
}
@ConditionalOnBusEnabled
@ConditionalOnClass({ Schema.class, ProtostuffIOUtil.class })
protected static class BusProtoStuffAutoConfiguration {
/**
*
* @return the protostuff io message converter
*/
@Bean
public MessageConverter busProtoBufConverter() {
return new BusProtoStuffMessageConverter();
}
}
}

View File

@@ -1,66 +0,0 @@
/**
* 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.eventbus;
import java.util.concurrent.Executor;
import org.eclipse.hawkbit.eventbus.EventBusSubscriberProcessor;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
/**
* Auto configuration for the event bus.
*
*/
@Configuration
public class EventBusAutoConfiguration {
@Autowired
@Qualifier("asyncExecutor")
private Executor executor;
/**
* Server internal eventBus that allows parallel event processing if the
* subscriber is marked as so.
*
* @return eventbus bean
*/
@Bean
@ConditionalOnMissingBean
public EventBus eventBus() {
return new AsyncEventBus(executor);
}
/**
* @return the {@link EventBusSubscriberProcessor} to find classes annotated
* with {@link EventSubscriber}.
*/
@Bean
@ConditionalOnMissingBean
public EventBusSubscriberProcessor eventBusSubscriberProcessor() {
return new EventBusSubscriberProcessor();
}
/**
* @return the singleton instance of the {@link EventBusHolder}
*/
@Bean
public EventBusHolder eventBusHolder() {
return EventBusHolder.getInstance();
}
}

View File

@@ -10,7 +10,7 @@ package org.eclipse.hawkbit.autoconfigure.repository;
import org.eclipse.hawkbit.EnableJpaRepository;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.jpa.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;

View File

@@ -23,7 +23,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
@@ -47,12 +47,10 @@ import org.eclipse.hawkbit.tenancy.TenantAware;
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.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@@ -436,8 +434,7 @@ public class SecurityManagedConfiguration {
private DdiSecurityProperties ddiSecurityConfiguration;
@Autowired
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
private Cache downloadIdCache;
private DownloadIdCache downloadIdCache;
@Override
protected void configure(final HttpSecurity http) throws Exception {

View File

@@ -9,15 +9,20 @@
package org.eclipse.hawkbit.autoconfigure.ui;
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.push.HawkbitEventProvider;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.vaadin.spring.annotation.EnableVaadinExtensions;
import org.vaadin.spring.events.annotation.EnableEventBus;
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
import com.vaadin.spring.annotation.UIScope;
/**
* The hawkbit-ui autoconfiguration.
*/
@@ -48,4 +53,22 @@ public class UIAutoConfiguration {
return new HawkbitEventProvider();
}
/**
* The UI scoped event push strategy. Session scope is necessary, that every
* UI has an own strategy.
*
* @param applicationContext
* the context to add the listener
*
* @return the provider bean
*/
@Bean
@ConditionalOnMissingBean
@UIScope
public EventPushStrategy eventPushStrategy(final ConfigurableApplicationContext applicationContext) {
final DelayedEventBusPushStrategy delayedEventBusPushStrategy = new DelayedEventBusPushStrategy();
applicationContext.addApplicationListener(delayedEventBusPushStrategy);
return delayedEventBusPushStrategy;
}
}

View File

@@ -24,28 +24,12 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@Configuration
public class WebMvcAutoConfiguration extends WebMvcConfigurerAdapter {
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* #configurePathMatch
* (org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
*/
@Override
public void configurePathMatch(final PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
configurer.setUseRegisteredSuffixPatternMatch(false);
}
/*
* (non-Javadoc)
*
* @see org.springframework.web.servlet.config.annotation.
* WebMvcConfigurerAdapter# configureContentNegotiation
* (org.springframework.web.servlet.config.annotation.
* ContentNegotiationConfigurer)
*/
@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);

View File

@@ -7,9 +7,8 @@ org.eclipse.hawkbit.autoconfigure.url.PropertyHostnameResolverAutoConfiguration,
org.eclipse.hawkbit.autoconfigure.web.WebMvcAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.cache.CacheAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.cache.DownloadIdCacheAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.eventbus.EventBusAutoConfiguration,\
org.eclipse.hawkbit.autoconfigure.event.EventPublisherAutoConfiguration,\
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.security.InMemoryUserManagementConfiguration

View File

@@ -14,6 +14,19 @@ security.basic.realm=HawkBit
security.user.name=admin
security.user.password=admin
# Spring cloud bus and stream
spring.cloud.bus.enabled=false
# Disable Cloud Bus default events
spring.cloud.bus.env.enabled=false
spring.cloud.bus.ack.enabled=false
spring.cloud.bus.trace.enabled=false
spring.cloud.bus.refresh.enabled=false
# Disable Cloud Bus endpoints
endpoints.spring.cloud.bus.refresh.enabled=false
endpoints.spring.cloud.bus.env.enabled=false
# Spring cloud bus and stream END
### JPA / Datasource - START
spring.jpa.database=H2
spring.jpa.show-sql=false

View File

@@ -1,81 +0,0 @@
<!--
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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-cache-redis</artifactId>
<name>hawkBit :: Redis Cache Manager</name>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-api</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.allure</groupId>
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,118 +0,0 @@
/**
* 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.cache;
import org.eclipse.hawkbit.cache.eventbus.EventDistributor;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
/**
* The spring Redis configuration which is enabled by using the profile
* {@code redis} to use a Redis server as cache.
*
*/
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfiguration {
@Autowired
private RedisProperties redisProperties;
@Autowired
private TenantAware tenantAware;
/**
* @return the {@link EventDistributor} to distribute and consume the events
* from Redis
*/
@Bean
public EventDistributor eventDistributor() {
return new EventDistributor();
}
/**
* @return the spring redis cache manager.
*/
@Bean
@Primary
public CacheManager cacheManager() {
return new TenantAwareCacheManager(directCacheManager(), tenantAware);
}
/**
*
* @return bean for the direct cache manager.
*/
@Bean(name = "directCacheManager")
public CacheManager directCacheManager() {
return new RedisCacheManager(redisTemplate());
}
/**
* @return the redis connection factory to create a redis connection based
* on the {@link RedisProperties}
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
final JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisProperties.getHost());
factory.setPort(redisProperties.getPort());
factory.setUsePool(true);
return factory;
}
/**
* @return the spring {@link RedisTemplate} configured with the necessary
* object serializers
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new JdkSerializationRedisSerializer());
redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return redisTemplate;
}
/**
* @return the spring-redis message listener adapter to consume messages
* from the Redis server
*/
@Bean
public MessageListenerAdapter messageListenerAdapter() {
final MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(eventDistributor());
messageListenerAdapter.setSerializer(new JdkSerializationRedisSerializer());
return messageListenerAdapter;
}
/**
* @return the spring-redis message listener container to register the
* message listener adapter
*/
@Bean
public RedisMessageListenerContainer redisContainer() {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory());
container.addMessageListener(messageListenerAdapter(), eventDistributor().getTopics());
return container;
}
}

View File

@@ -1,60 +0,0 @@
/**
* 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.cache;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Bean which holds the necessary properties for configuring the Redis
* connection.
*
*/
@ConfigurationProperties("hawkbit.server.redis")
public class RedisProperties {
/**
* Redis server hostname.
*/
private String host;
/**
* Redis server port.
*/
private int port;
/**
* @return the host
*/
public String getHost() {
return host;
}
/**
* @param host
* the host to set
*/
public void setHost(final String host) {
this.host = host;
}
/**
* @return the port
*/
public int getPort() {
return port;
}
/**
* @param port
* the port to set
*/
public void setPort(final int port) {
this.port = port;
}
}

View File

@@ -1,29 +0,0 @@
/**
* 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.cache.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.hawkbit.cache.RedisConfiguration;
import org.springframework.context.annotation.Import;
/**
* Annotation to enable redis caching.
*
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(RedisConfiguration.class)
public @interface EnableRedis {
}

View File

@@ -1,140 +0,0 @@
/**
* 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.cache.eventbus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.eventbus.event.DistributedEvent;
import org.eclipse.hawkbit.eventbus.event.Event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* The distributor for events.
*
*/
@EventSubscriber
@Service
public class EventDistributor {
private static final Logger LOGGER = LoggerFactory.getLogger(EventDistributor.class);
/**
* the node id to filter self published events in the redis message
* subscriber.
*/
private static final String NODE_ID = UUID.randomUUID().toString();
private static final String DISTRIBUTION_CHANNEL_TOPIC = "com/bosch/sp/distEvent";
private static final String SEND_DISTRIBUTION_CHANNEL = DISTRIBUTION_CHANNEL_TOPIC + "/" + NODE_ID;
private static final String SUB_DISTRIBUTION_CHANNEL = DISTRIBUTION_CHANNEL_TOPIC + "*";
@Autowired(required = false)
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private EventBus eventBus;
/**
* consumes all {@link DistributedEvent}s posted on the {@link EventBus} and
* distribute them to the Redis server.
*
* @param event
* the distributed event posted on the {@link EventBus}
*/
@Subscribe
public void distribute(final DistributedEvent event) {
if (redisTemplate != null) {
if (!NODE_ID.equals(event.getNodeId())) {
logDistributingEvent(event, SEND_DISTRIBUTION_CHANNEL);
event.setOriginNodeId(NODE_ID);
redisTemplate.convertAndSend(SEND_DISTRIBUTION_CHANNEL, event);
}
} else {
logNotDistributingEvent(event, SEND_DISTRIBUTION_CHANNEL);
}
}
/**
* message listener callback method for the {@link MessageListenerAdapter}
* which calls the method in case a message is received from the Redis
* server of the type {@link DistributedEventWrapper}.
*
* @param event
* the {@link DistributedEventWrapper} event which was received
* by the Redis client
* @param channel
* the on which the event was received
*/
public void handleMessage(final DistributedEvent event, final String channel) {
LOGGER.trace("retrieving event from redis {} on channel {}, posting to the local event bus", event, channel);
if (!NODE_ID.equals(event.getOriginNodeId())) {
event.setNodeId(NODE_ID);
eventBus.post(event);
}
}
/**
* @return a collection of all topics which this Redis message listener
* wants to subscribe
*/
public Collection<Topic> getTopics() {
final List<Topic> topics = new ArrayList<>();
topics.add(new PatternTopic(SUB_DISTRIBUTION_CHANNEL));
return topics;
}
private static void logDistributingEvent(final Event event, final String channel) {
LOGGER.trace("distributing event {} from node {} to topic {}", event, NODE_ID, channel);
}
private static void logNotDistributingEvent(final Event event, final String channel) {
LOGGER.debug("no redis template configured, event {} will not be distributed to channel {} from node {}", event,
channel, NODE_ID);
}
/**
* testing purposes.
*
* @param redisTemplate
* the redisTemplate to set
*/
void setRedisTemplate(final RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* testing purposes.
*
* @param eventBus
* the eventBus to set
*/
void setEventBus(final EventBus eventBus) {
this.eventBus = eventBus;
}
/**
* @return the nodeId
*/
static String getNodeId() {
return NODE_ID;
}
}

View File

@@ -1,228 +0,0 @@
/**
* 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.cache.eventbus;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.Collection;
import org.eclipse.hawkbit.eventbus.event.EntityEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.Topic;
import org.springframework.hateoas.Identifiable;
import com.google.common.eventbus.EventBus;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Cache")
@Stories("EventDistributor Test")
@RunWith(MockitoJUnitRunner.class)
// TODO: create description annotations
public class EventDistributorTest {
@Mock
private RedisTemplate<String, Object> redisTemplateMock;
@Mock
private EventBus eventBusMock;
private EventDistributor underTest;
@Before
public void before() {
underTest = new EventDistributor();
underTest.setEventBus(eventBusMock);
underTest.setRedisTemplate(redisTemplateMock);
}
@Test
public void distributeDistributedEventSendsToRedis() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
underTest.distribute(event);
// origin node ID should be set by distributing the event
assertThat(event.getOriginNodeId()).isNotNull();
verify(redisTemplateMock).convertAndSend(anyString(), eq(event));
}
@Test
public void dontDistributeDistributedEventIfSameNode() {
final String knownNodeId = EventDistributor.getNodeId();
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
event.setNodeId(knownNodeId);
// test
underTest.distribute(event);
assertThat(event.getOriginNodeId()).isNull();
verify(redisTemplateMock, times(0)).convertAndSend(anyString(), eq(event));
}
@Test
public void handleDistributedMessageFromRedis() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
final String knownChannel = "someChannel";
underTest.handleMessage(event, knownChannel);
assertThat(event.getNodeId()).isEqualTo(EventDistributor.getNodeId());
verify(eventBusMock).post(eq(event));
}
@Test
public void handleDistributedMessageFilteredIfSameNodeId() {
final DownloadProgressEvent event = new DownloadProgressEvent("tenant", 123L, 500L, 100L, 200L);
final String knownChannel = "someChannel";
event.setOriginNodeId(EventDistributor.getNodeId());
underTest.handleMessage(event, knownChannel);
assertThat(event.getNodeId()).isNull();
verify(eventBusMock, times(0)).post(eq(event));
}
@Test
public void subscribedTopicsContains2PatternTopics() {
final Collection<Topic> topics = underTest.getTopics();
assertThat(topics).hasSize(1);
}
private class TestEntityEvent implements EntityEvent {
private String originNodeId;
private String nodeId;
private final String tenant;
private final MyEntity entity;
/**
* @param myEntity
*/
public TestEntityEvent(final MyEntity myEntity, final String tenant) {
this.entity = myEntity;
this.tenant = tenant;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.Event#getRevision()
*/
@Override
public long getRevision() {
return 0;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#getOriginNodeId()
*/
@Override
public String getOriginNodeId() {
return originNodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setOriginNodeId(
* java. lang.String)
*/
@Override
public void setOriginNodeId(final String originNodeId) {
this.originNodeId = originNodeId;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.NodeAware#getNodeId()
*/
@Override
public String getNodeId() {
return nodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setNodeId(java.
* lang. String)
*/
@Override
public void setNodeId(final String nodeId) {
this.nodeId = nodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity(java.
* lang. Class)
*/
@Override
public <E> E getEntity(final Class<E> entityClass) {
return entityClass.cast(entity);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getEntity()
*/
@Override
public Object getEntity() {
return entity;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
*/
@Override
public String getTenant() {
return tenant;
}
}
private class MyEntity implements Identifiable<String> {
private final String id = "123";
/*
* (non-Javadoc)
*
* @see org.springframework.hateoas.Identifiable#getId()
*/
@Override
public String getId() {
return id;
}
}
}

View File

@@ -1,36 +0,0 @@
/**
* 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.cache.redis;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.cache.RedisProperties;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Cache")
@Stories("Redis Properties Test")
public class RedisPropertiesTest {
@Test
public void setAndGetProps() {
final String knownHost = "bumlux";
final int knownPort = 1234;
final RedisProperties underTest = new RedisProperties();
underTest.setHost(knownHost);
underTest.setPort(knownPort);
assertThat(underTest.getHost()).isEqualTo(knownHost);
assertThat(underTest.getPort()).isEqualTo(knownPort);
}
}

View File

@@ -53,6 +53,16 @@
<artifactId>allure-junit-adaptor</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>

View File

@@ -0,0 +1,57 @@
/**
* 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.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
/**
* A default implementation of the {@link DownloadIdCache} which uses the
* {@link CacheManager} implementation to store the download-ids.
*/
public class DefaultDownloadIdCache implements DownloadIdCache {
static final String DOWNLOAD_ID_CACHE = "DowonloadIdCache";
private final CacheManager cacheManager;
/**
* @param cacheManager
* the underlying cache-manager to store the download-ids
*/
@Autowired
public DefaultDownloadIdCache(final CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public void put(final String downloadId, final DownloadArtifactCache object) {
getCache().put(downloadId, object);
}
@Override
public DownloadArtifactCache get(final String downloadId) {
final ValueWrapper valueWrapper = getCache().get(downloadId);
return (valueWrapper == null) ? null : (DownloadArtifactCache) valueWrapper.get();
}
@Override
public void evict(final String downloadId) {
getCache().evict(downloadId);
}
private Cache getCache() {
if (cacheManager instanceof TenancyCacheManager) {
return ((TenancyCacheManager) cacheManager).getDirectCache(DOWNLOAD_ID_CACHE);
}
return cacheManager.getCache(DOWNLOAD_ID_CACHE);
}
}

View File

@@ -9,10 +9,7 @@
package org.eclipse.hawkbit.cache;
/**
* Cache Object for download a Artifact.
*
*
*
* Cache Object for downloading an artifact.
*/
public class DownloadArtifactCache {

View File

@@ -0,0 +1,57 @@
/**
* 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.cache;
/**
* A interface declaration of the download-id-cache which allows to store
* volatile generated download-IDs used to have a single unique download-request
* e.g. for distributed download-server.
*
* A valid download-id is created during a successful download-authorization
* request e.g. from a download-server. In the DMF response a unique
* download-URL containing a generated download-id which can be used to download
* the artifact using this single download-url.
*
* The {@link DownloadIdCache} handles storing this unique download-id from the
* DMF authorization request until the actual artifact download-request via HTTP
* with the unique ID is performed.
*
*/
public interface DownloadIdCache {
/**
* Puts a given artifact cache object with the given downloadId key into the
* cache.
*
* @param downloadId
* the ID to store the cache object to look it up later on
* @param downloadArtifactCacheObject
* the object to store into the cache
*/
void put(final String downloadId, final DownloadArtifactCache downloadArtifactCacheObject);
/**
* Retrieves a {@link DownloadArtifactCache} by a given downloadId.
*
* @param downloadId
* the ID to retrieve the artifact cache object
* @return the found {@link DownloadArtifactCache} or {@code null} if none
* exists for the given ID
*/
DownloadArtifactCache get(final String downloadId);
/**
* Evicts a {@link DownloadArtifactCache} for the given downloadId
*
* @param downloadId
* the ID to be evicted
*/
void evict(String downloadId);
}

View File

@@ -10,9 +10,6 @@ package org.eclipse.hawkbit.cache;
/**
* The type of the id which is saved.
*
*
*
*/
public enum DownloadType {
BY_SHA1

View File

@@ -12,7 +12,6 @@ import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
/**
*
* A cache interface which handles multi tenancy.
*/
public interface TenancyCacheManager extends CacheManager {
@@ -36,5 +35,4 @@ public interface TenancyCacheManager extends CacheManager {
* the tenant to evict caches
*/
void evictCaches(final String tenant);
}

View File

@@ -8,8 +8,9 @@
*/
package org.eclipse.hawkbit.cache;
import static java.util.Collections.emptyList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -25,10 +26,6 @@ import org.springframework.cache.CacheManager;
*
* Additionally it also provide functionality to retrieve all caches overall
* tenants at once, for monitoring and system access.
*
*
*
*
*/
public class TenantAwareCacheManager implements TenancyCacheManager {
@@ -39,41 +36,39 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
private final TenantAware tenantAware;
/**
* Constructor.
*
* @param delegate
* the {@link CacheManager} to delegate to.
* @param tenantAware
* the tenant aware to retrieve the current tenant
*/
public TenantAwareCacheManager(final CacheManager delegate, final TenantAware tenantAware) {
this.delegate = delegate;
this.tenantAware = tenantAware;
this.delegate = delegate;
}
@Override
public Cache getCache(final String name) {
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
if (isTenantInvalid(currentTenant)) {
return null;
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return null;
}
return delegate.getCache(currentTenant + TENANT_CACHE_DELIMITER + name);
return delegate.getCache(buildKey(currentTenant, name));
}
@Override
public Collection<String> getCacheNames() {
String currentTenant = tenantAware.getCurrentTenant();
if (currentTenant == null) {
return Collections.emptyList();
if (isTenantInvalid(currentTenant)) {
return emptyList();
}
currentTenant = currentTenant.toUpperCase();
if (currentTenant.contains(TENANT_CACHE_DELIMITER)) {
return Collections.emptyList();
}
return getCacheNames(currentTenant);
}
@@ -91,17 +86,17 @@ public class TenantAwareCacheManager implements TenancyCacheManager {
return delegate.getCache(name);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.cache.TenancyCacheManager#evictCaches(java.
* lang. String)
*/
@Override
public void evictCaches(final String tenant) {
getCacheNames(tenant)
.forEach(cachename -> delegate.getCache(tenant + TENANT_CACHE_DELIMITER + cachename).clear());
getCacheNames(tenant).forEach(cachename -> delegate.getCache(buildKey(tenant, cachename)).clear());
}
private boolean isTenantInvalid(final String tenant) {
return tenant == null || tenant.contains(TENANT_CACHE_DELIMITER);
}
private String buildKey(final String tenant, final String cacheName) {
return tenant + TENANT_CACHE_DELIMITER + cacheName;
}
private Collection<String> getCacheNames(final String tenant) {

View File

@@ -1,40 +0,0 @@
/**
* 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.eventbus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.Subscribe;
/**
* Catches all dead events by means of events with no fitting subscriber on the
* bus.
*
*
*
*/
@EventSubscriber
@Service
public class DeadEventListener {
private static final Logger LOG = LoggerFactory.getLogger(DeadEventListener.class);
/**
* Listens for dead vents and prints them into LOG.
*
* @param event
* to print
*/
@Subscribe
public void listen(final DeadEvent event) {
LOG.info("DeadEvent on bus! {}", event.getEvent());
}
}

View File

@@ -1,88 +0,0 @@
/**
* 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.eventbus;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* An {@link BeanPostProcessor} implementation which registers all beans as a
* event bus subscriber if the classes are annotated with
* {@link EventSubscriber} and have at least one method annotated with the
* guava's {@link Subscribe} annoation.
*
*
*/
public class EventBusSubscriberProcessor implements BeanPostProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(EventBusSubscriberProcessor.class);
@Autowired
private EventBus eventBus;
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#
* postProcessBeforeInitialization (java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) {
return bean;
}
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.config.BeanPostProcessor#
* postProcessAfterInitialization( java.lang.Object, java.lang.String)
*/
@Override
public Object postProcessAfterInitialization(final Object bean, final String beanName) {
final Class<? extends Object> beanClass = bean.getClass();
final EventSubscriber eventSubscriber = beanClass.getAnnotation(EventSubscriber.class);
if (eventSubscriber != null) {
LOGGER.trace("Found bean {} with {} annotation ", bean.getClass().getName(),
EventSubscriber.class.getSimpleName());
final Method[] declaredMethods = beanClass.getDeclaredMethods();
for (final Method method : declaredMethods) {
final Subscribe subscriber = method.getAnnotation(Subscribe.class);
if (subscriber != null) {
LOGGER.trace("Found method {} for bean {} with {} annotation", method.getName(),
bean.getClass().getName(), Subscribe.class.getSimpleName());
eventBus.register(bean);
return bean;
}
}
}
if (eventSubscriber != null) {
LOGGER.debug("Found bean {} with {} annotation but without any method with necessary {} annotation",
bean.getClass().getName(), EventSubscriber.class.getSimpleName(), Subscribe.class.getSimpleName());
}
return bean;
}
/**
* package private setter for testing purposes.
*
* @param eventBus
* the event bus
*/
void setEventBus(final EventBus eventBus) {
this.eventBus = eventBus;
}
}

View File

@@ -1,39 +0,0 @@
/**
* 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.eventbus;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Marks an class as an event subscriber to listen on event on the event bus
* without explicit register this class to the event bus.
*
* <pre>
* &#064;EventSubscriber
* public class MySubscriber {
* &#064;Subscribe
* public void listen(MyEvent event) {
* System.out.println(&quot;event received: &quot; + event);
* }
* }
* </pre>
*
*
*
*
*/
@Target({ TYPE })
@Retention(RUNTIME)
public @interface EventSubscriber {
}

View File

@@ -1,105 +0,0 @@
/**
* 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.eventbus.event;
/**
* An abstract class of the {@link DistributedEvent} implementation which holds
* all the necessary information of distributing events to other nodes.
*
*
*
*
*/
public abstract class AbstractDistributedEvent implements DistributedEvent {
private static final long serialVersionUID = 1L;
private final long revision;
private String originNodeId;
private String nodeId;
private final String tenant;
/**
*
* @param revision
* the revision of this event
* @param tenant
* the tenant for this event
*/
protected AbstractDistributedEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setOriginNodeId(java.
* lang. String)
*/
@Override
public void setOriginNodeId(final String originNodeId) {
this.originNodeId = originNodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#setNodeId(java.lang.
* String)
*/
@Override
public void setNodeId(final String nodeId) {
this.nodeId = nodeId;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.hawkbit.server.eventbus.event.NodeAware#getOriginNodeId()
*/
@Override
public String getOriginNodeId() {
return this.originNodeId;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.NodeAware#getNodeId()
*/
@Override
public String getNodeId() {
return this.nodeId;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.Event#getRevision()
*/
@Override
public long getRevision() {
return revision;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.hawkbit.server.eventbus.event.EntityEvent#getTenant()
*/
@Override
public String getTenant() {
return tenant;
}
}

View File

@@ -1,44 +0,0 @@
/**
* 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.eventbus.event;
/**
* Abstract event definition class which holds the necessary revsion and tenant
* information which every event needs.
*
* @see AbstractDistributedEvent for events which should be distributed to other
* cluster nodes
*/
public class DefaultEvent implements Event {
private final long revision;
private final String tenant;
/**
* @param revision
* the revision number of the event
* @param tenant
* the tenant of the event
*/
protected DefaultEvent(final long revision, final String tenant) {
this.revision = revision;
this.tenant = tenant;
}
@Override
public long getRevision() {
return revision;
}
@Override
public String getTenant() {
return tenant;
}
}

View File

@@ -1,23 +0,0 @@
/**
* 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.eventbus.event;
import java.io.Serializable;
/**
* Marks an event to as an distributed event which will be distributed to other
* nodes.
*
*
*
*
*/
public interface DistributedEvent extends Event, NodeAware, Serializable {
}

View File

@@ -1,48 +0,0 @@
/**
* 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.eventbus.event;
/**
* An event interface which declares event types that an entity has been
* changed. {@link EntityEvent}s should not implement {@link DistributedEvent}
* due all {@link EntityEvent}s will be distributed to other nodes.
*
* Retrieving an {@link EntityEvent} on a different node the entity will be load
* lazy.
*
*
*
*
*/
public interface EntityEvent extends Event, NodeAware {
/**
* A typesafe way to retrieve the entity from the event, which might be
* loaded lazy in case the event has been distributed from another node.
*
* @param entityClass
* the class of the entity to retrieve
* @return the entity might be lazy loaded. Might be {@code null} in case
* the entity e.g. is queried lazy on a different node and has been
* already deleted from the database
* @throws ClassCastException
* in case a wrong entity class is given for this event
*/
<E> E getEntity(Class<E> entityClass);
/**
* An unsafe way to retrieve the entity from this event which might be
* loaded lazy in case the event has been distributed from another node.
*
* @return the entity might be lazy loaded. Might be {@code null} in case
* the entity e.g. is queried lazy on a different node and has been
* already deleted from the database
*/
Object getEntity();
}

View File

@@ -1,32 +0,0 @@
/**
* 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.eventbus.event;
/**
* An event declaration which holds an revision for each event so consumers have
* the chance to know if they might already retrieved an newer event.
*
*
*
*
*/
public interface Event {
/**
* @return the revision of this event which should be increment or each new
* event in case the event have a causalität. Might be {@code -1} in
* case the events does not provide any revision.
*/
long getRevision();
/**
* @return the tenant of the entity.
*/
String getTenant();
}

View File

@@ -1,52 +0,0 @@
/**
* 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.eventbus.event;
/**
* Interface to be implemented by events which are distributed to other nodes
* where it's necessary to know which node sent an event and which nodes
* retrieved the event from which node. Using the EventDistributor the
* implementation only needs to contain the necessary node IDs, setting and
* retrieving the node IDs is transparent by the EventDistributor so the event
* distributor does not hang in an endless loop of distributing the events which
* self posted.
*
*
*
*
*/
public interface NodeAware {
/**
* @return the origin node ID in case the event has been forwarded to other
* nodes or {@code null} if the event has not been forwarded to
* other nodes
*/
String getOriginNodeId();
/**
* @param originNodeId
* the origin node ID where this event has been sent originally
*/
void setOriginNodeId(String originNodeId);
/**
* @return the node ID which is processing this event locally, set by the
* EventDistributor so he can determine if this event has been
* received by another node and is processing on the current node.
*/
String getNodeId();
/**
* @param nodeId
* the ID of the node this event is processing.
*/
void setNodeId(String nodeId);
}

View File

@@ -0,0 +1,124 @@
/**
* 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.cache;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cache")
@Stories("Download ID Cache")
@RunWith(MockitoJUnitRunner.class)
public class DefaultDownloadIdCacheTest {
@Mock
private CacheManager cacheManagerMock;
@Mock
private TenancyCacheManager tenancyCacheManagerMock;
@Mock
private Cache cacheMock;
@Captor
private ArgumentCaptor<String> cacheManagerKeyCaptor;
@Captor
private ArgumentCaptor<DownloadArtifactCache> cacheManagerValueCaptor;
private DefaultDownloadIdCache underTest;
private final String knownKey = "12345";
@Before
public void before() {
underTest = new DefaultDownloadIdCache(cacheManagerMock);
when(cacheManagerMock.getCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE)).thenReturn(cacheMock);
when(tenancyCacheManagerMock.getDirectCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE)).thenReturn(cacheMock);
}
@Test
@Description("Verifies that putting key and value is delegated to the CacheManager implementation")
public void putKeyAndValueIsDelegatedToCacheManager() {
final DownloadArtifactCache value = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
underTest.put(knownKey, value);
verify(cacheMock).put(cacheManagerKeyCaptor.capture(), cacheManagerValueCaptor.capture());
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
assertThat(cacheManagerValueCaptor.getValue()).isEqualTo(value);
}
@Test
@Description("Verifies that evicting a key is delegated to the CacheManager implementation")
public void evictKeyIsDelegatedToCacheManager() {
underTest.evict(knownKey);
verify(cacheMock).evict(cacheManagerKeyCaptor.capture());
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
}
@Test
@Description("Verifies that retrieving a value for a specific key is delegated to the CacheManager implementation")
public void getValueReturnsTheAssociatedValueForKey() {
final String knownKey = "12345";
final DownloadArtifactCache knownValue = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
when(cacheMock.get(knownKey)).thenReturn(new SimpleValueWrapper(knownValue));
final DownloadArtifactCache downloadArtifactCache = underTest.get(knownKey);
assertThat(downloadArtifactCache).isEqualTo(knownValue);
}
@Test
@Description("Verifies that retrieving a null value for a specific key is delegated to the CacheManager implementation")
public void getValueReturnsNullIfNoKeyIsAssociated() {
when(cacheMock.get(knownKey)).thenReturn(new SimpleValueWrapper(null));
final DownloadArtifactCache downloadArtifactCache = underTest.get(knownKey);
assertThat(downloadArtifactCache).isNull();
}
@Test
@Description("Verifies that TenancyCacheManager is using direct cache because download-ids are global unique and don't need to run as tenant aware")
public void tenancyCacheManagerIsUsingDirectCache() {
underTest = new DefaultDownloadIdCache(tenancyCacheManagerMock);
final DownloadArtifactCache value = new DownloadArtifactCache(DownloadType.BY_SHA1, knownKey);
underTest.put(knownKey, value);
verify(cacheMock).put(cacheManagerKeyCaptor.capture(), cacheManagerValueCaptor.capture());
verify(tenancyCacheManagerMock).getDirectCache(DefaultDownloadIdCache.DOWNLOAD_ID_CACHE);
assertThat(cacheManagerKeyCaptor.getValue()).isEqualTo(knownKey);
assertThat(cacheManagerValueCaptor.getValue()).isEqualTo(value);
}
}

View File

@@ -1,75 +0,0 @@
/**
* 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.eventbus;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Cluster Event Bus")
@Stories("EventBus Subscriber Processor Test")
@RunWith(MockitoJUnitRunner.class)
// TODO: create description annotations
public class EventBusSubscriberProcessorTest {
@Mock
private EventBus eventBusMock;
private final EventBusSubscriberProcessor postProcessorUnderTest = new EventBusSubscriberProcessor();
@Before
public void before() {
reset(eventBusMock);
postProcessorUnderTest.setEventBus(eventBusMock);
}
@Test
public void correctAnnotatedClassAndMethodIsRegistered() {
final TestEventSubscriberClass testEventSubscriberClass = new TestEventSubscriberClass();
postProcessorUnderTest.postProcessAfterInitialization(testEventSubscriberClass, "correctEventSubscriber");
verify(eventBusMock, times(1)).register(testEventSubscriberClass);
}
@Test
public void eventSubscriberWithoutMethodAnnotationIsNotRegistered() {
final TestWrongEventSubscriberClass testEventSubscriberClass = new TestWrongEventSubscriberClass();
postProcessorUnderTest.postProcessAfterInitialization(testEventSubscriberClass, "correctEventSubscriber");
verify(eventBusMock, times(0)).register(testEventSubscriberClass);
}
@EventSubscriber
@Service
private class TestEventSubscriberClass {
@Subscribe
public void subscribe(final String s) {
}
}
@EventSubscriber
@Service
private class TestWrongEventSubscriberClass {
public void methodWithoutAnnotation(final String s) {
}
}
}

View File

@@ -37,9 +37,5 @@
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -67,22 +67,6 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@@ -103,13 +87,6 @@
<artifactId>spring-security-config</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-repository-jpa</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-http-security</artifactId>

View File

@@ -30,7 +30,8 @@ import java.util.Locale;
import java.util.TimeZone;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.eclipse.hawkbit.ddi.rest.resource.DdiArtifactDownloadTest.DownloadTestConfiguration;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -41,15 +42,15 @@ import org.eclipse.hawkbit.rest.AbstractRestIntegrationTestWithMongoDB;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import com.google.common.base.Charsets;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.net.HttpHeaders;
import ru.yandex.qatools.allure.annotations.Description;
@@ -61,6 +62,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
*/
@Features("Component Tests - Direct Device Integration API")
@Stories("Artifact Download Resource")
@SpringApplicationConfiguration(classes = DownloadTestConfiguration.class)
public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMongoDB {
private static final int ARTIFACT_SIZE = 5 * 1024 * 1024;
@@ -69,9 +71,8 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
LOG = LoggerFactory.getLogger(DdiArtifactDownloadTest.class);
}
private volatile int downLoadProgress = 0;
private volatile long shippedBytes = 0;
private volatile long shippedBytesTotal = 0;
private volatile static int downLoadProgress = 0;
private volatile static long shippedBytes = 0;
private final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
@@ -80,9 +81,6 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
}
@Autowired
private EventBus eventBus;
@Test
@Description("Tests non allowed requests on the artifact ressource, e.g. invalid URI, wrong if-match, wrong command.")
public void invalidRequestsOnArtifactResource() throws Exception {
@@ -252,8 +250,6 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
public void downloadArtifactThroughFileName() throws Exception {
downLoadProgress = 1;
shippedBytes = 0;
shippedBytesTotal = 0;
eventBus.register(this);
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
// create target
@@ -293,7 +289,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
// download complete
assertThat(downLoadProgress).isEqualTo(10);
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE);
assertThat(shippedBytes).isEqualTo(ARTIFACT_SIZE);
}
@Test
@@ -332,8 +328,6 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
public void downloadArtifactByNameFailsIfNotAuthenticated() throws Exception {
downLoadProgress = 1;
shippedBytes = 0;
shippedBytesTotal = 0;
eventBus.register(this);
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
@@ -357,7 +351,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
.andExpect(status().isNotFound());
assertThat(downLoadProgress).isEqualTo(1);
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(0L);
assertThat(shippedBytes).isEqualTo(0L);
}
@Test
@@ -366,8 +360,6 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
public void downloadArtifactByNameByNamedController() throws Exception {
downLoadProgress = 1;
shippedBytes = 0;
shippedBytesTotal = 0;
eventBus.register(this);
assertThat(softwareManagement.findSoftwareModulesAll(pageReq)).hasSize(0);
@@ -414,7 +406,7 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
// download complete
assertThat(downLoadProgress).isEqualTo(10);
assertThat(shippedBytes).isEqualTo(shippedBytesTotal).isEqualTo(ARTIFACT_SIZE);
assertThat(shippedBytes).isEqualTo(ARTIFACT_SIZE);
}
@Test
@@ -573,11 +565,23 @@ public class DdiArtifactDownloadTest extends AbstractRestIntegrationTestWithMong
.isEqualTo(new String(artifact.getMd5Hash() + " file1.tar.bz2").getBytes(Charsets.US_ASCII));
}
@Subscribe
public static class DownloadTestConfiguration {
@Bean
public Listener cancelEventHandlerStubBean() {
return new Listener();
}
}
private static class Listener {
@EventListener(classes = DownloadProgressEvent.class)
public void listen(final DownloadProgressEvent event) {
downLoadProgress++;
shippedBytes += event.getShippedBytesSinceLast();
shippedBytesTotal = event.getShippedBytesOverall();
}
}
}

View File

@@ -31,7 +31,6 @@ import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Test;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import ru.yandex.qatools.allure.annotations.Description;
@@ -74,7 +73,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
// get update action anyway
mvc.perform(get("/{tenant}/controller/v1/4712/deploymentBase/" + updateAction.getId(),
tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(updateAction.getId()))))
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced")))
@@ -118,7 +117,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant()
@@ -150,7 +149,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
@@ -170,7 +169,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
get("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction.getId(), tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(updateAction.getId()))));
assertThat(targetManagement.findTargetByControllerID("4712").getTargetInfo().getLastTargetQuery())
@@ -360,14 +359,14 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
get("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction.getId(), tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(updateAction.getId()))));
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(6);
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
@@ -386,14 +385,14 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
assertThat(deploymentManagement.findActionsByTarget(savedTarget)).hasSize(3);
mvc.perform(get("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction2.getId(),
tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction2.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(updateAction2.getId()))));
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(8);
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.cancelAction.href",
equalTo("http://localhost/" + tenantAware.getCurrentTenant()
@@ -426,7 +425,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
mvc.perform(get("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction3.getId(),
tenantAware.getCurrentTenant()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(cancelAction3.getId()))))
.andExpect(jsonPath("$.cancelAction.stopId", equalTo(String.valueOf(updateAction3.getId()))));
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(12);
@@ -435,7 +434,7 @@ public class DdiCancelActionTest extends AbstractRestIntegrationTest {
mvc.perform(post("/{tenant}/controller/v1/4712/cancelAction/" + cancelAction3.getId() + "/feedback",
tenantAware.getCurrentTenant())
.content(JsonBuilder.cancelActionFeedback(cancelAction3.getId().toString(), "closed"))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON_UTF8))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(deploymentManagement.countActionStatusAll()).isEqualTo(13);

View File

@@ -52,7 +52,7 @@ public class DdiConfigDataTest extends AbstractRestIntegrationTest {
final long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.configData.href", equalTo(
"http://localhost/" + tenantAware.getCurrentTenant() + "/controller/v1/4712/configData")));
@@ -75,7 +75,7 @@ public class DdiConfigDataTest extends AbstractRestIntegrationTest {
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.configData.href").doesNotExist());
}

View File

@@ -27,13 +27,13 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.RandomUtils;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
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.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.RepositoryModelConstants;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
@@ -44,7 +44,6 @@ import org.fest.assertions.core.Condition;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
@@ -136,7 +135,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", startsWith("http://localhost/"
+ tenantAware.getCurrentTenant() + "/controller/v1/4712/deploymentBase/" + uaction.getId())));
@@ -155,7 +154,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
get("/{tenant}/controller/v1/4712/deploymentBase/" + uaction.getId(), tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(action.getId()))))
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced")))
@@ -236,7 +235,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
MvcResult mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn();
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF)).andReturn();
final String urlBeforeSwitch = JsonPath.compile("_links.deploymentBase.href")
.read(mvcResult.getResponse().getContentAsString()).toString();
@@ -244,7 +243,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
// Time is not yet over, so we should see the same URL
mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn();
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF)).andReturn();
assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString())
.toString()).isEqualTo(urlBeforeSwitch)
.startsWith("http://localhost/" + tenantAware.getCurrentTenant()
@@ -255,7 +254,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
mvcResult = mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON)).andReturn();
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF)).andReturn();
assertThat(JsonPath.compile("_links.deploymentBase.href").read(mvcResult.getResponse().getContentAsString())
.toString()).isNotEqualTo(urlBeforeSwitch);
@@ -300,7 +299,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", startsWith("http://localhost/"
+ tenantAware.getCurrentTenant() + "/controller/v1/4712/deploymentBase/" + uaction.getId())));
@@ -319,7 +318,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
get("/{tenant}/controller/v1/4712/deploymentBase/" + uaction.getId(), tenantAware.getCurrentTenant())
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(action.getId()))))
.andExpect(jsonPath("$.deployment.download", equalTo("attempt")))
.andExpect(jsonPath("$.deployment.update", equalTo("attempt")))
@@ -424,7 +423,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4712", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href", startsWith("http://localhost/"
+ tenantAware.getCurrentTenant() + "/controller/v1/4712/deploymentBase/" + uaction.getId())));
@@ -441,7 +440,7 @@ public class DdiDeploymentBaseTest extends AbstractRestIntegrationTestWithMongoD
mvc.perform(get("/{tenant}/controller/v1/4712/deploymentBase/{actionId}", tenantAware.getCurrentTenant(),
uaction.getId()).accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", equalTo(String.valueOf(action.getId()))))
.andExpect(jsonPath("$.deployment.download", equalTo("forced")))
.andExpect(jsonPath("$.deployment.update", equalTo("forced")))

View File

@@ -122,7 +122,7 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
final long current = System.currentTimeMillis();
mvc.perform(get("/default-tenant/controller/v1/4711")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")));
assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getLastTargetQuery())
.isGreaterThanOrEqualTo(current);
@@ -154,7 +154,7 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
securityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:02:00")));
return null;
});
@@ -165,7 +165,7 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
public void rootRsNotModified() throws Exception {
final String etag = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00"))).andReturn().getResponse()
.getHeader("ETag");
@@ -182,7 +182,7 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header("If-None-Match", etag).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant()
@@ -215,7 +215,7 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())
.header("If-None-Match", etagWithFirstUpdate).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")))
.andExpect(jsonPath("$._links.deploymentBase.href",
startsWith("http://localhost/" + tenantAware.getCurrentTenant()
@@ -236,8 +236,9 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
final long current = System.currentTimeMillis();
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaTypes.HAL_JSON))
.andExpect(content().contentType(APPLICATION_JSON_HAL_UTF))
.andExpect(jsonPath("$.config.polling.sleep", equalTo("00:01:00")));
assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getLastTargetQuery())
.isLessThanOrEqualTo(System.currentTimeMillis());
assertThat(targetManagement.findTargetByControllerID("4711").getTargetInfo().getLastTargetQuery())

View File

@@ -7,6 +7,9 @@
# http://www.eclipse.org/legal/epl-v10.html
#
logging.level.=INFO
logging.level.org.eclipse.persistence=ERROR
spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value}
spring.data.mongodb.port=28017

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<!-- <Logger name="org.eclipse.hawkbit.rest.util.MockMvcResultPrinter" level="DEBUG" /> -->
<Root level="INFO">
<appender-ref ref="CONSOLE" />
</Root>
</configuration>

View File

@@ -57,10 +57,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
@@ -69,6 +65,8 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- Optional -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>

View File

@@ -15,6 +15,7 @@ import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.cache.DownloadType;
import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.ArtifactHash;
@@ -31,7 +32,6 @@ import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.cache.Cache;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
@@ -56,7 +56,7 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
private final ArtifactManagement artifactManagement;
private final Cache cache;
private final DownloadIdCache cache;
private final HostnameResolver hostnameResolver;
@@ -78,7 +78,7 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
*/
public AmqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate,
final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement,
final Cache cache, final HostnameResolver hostnameResolver,
final DownloadIdCache cache, final HostnameResolver hostnameResolver,
final ControllerManagement controllerManagement) {
super(rabbitTemplate);
this.authenticationManager = authenticationManager;
@@ -89,7 +89,7 @@ public class AmqpAuthenticationMessageHandler extends BaseAmqpService {
}
/**
* Executed on a authentication request.
* Executed on an authentication request.
*
* @param message
* the amqp message

View File

@@ -15,12 +15,13 @@ import java.util.concurrent.ScheduledExecutorService;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.dmf.amqp.api.AmqpSettings;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.security.DdiSecurityProperties;
import org.eclipse.hawkbit.security.SystemSecurityContext;
@@ -45,7 +46,7 @@ import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.Cache;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
@@ -74,6 +75,9 @@ public class AmqpConfiguration {
@Autowired
private ConnectionFactory rabbitConnectionFactory;
@Autowired(required = false)
private ServiceMatcher serviceMatcher;
@Configuration
@ConditionalOnMissingBean(ConnectionFactory.class)
@ConditionalOnProperty(prefix = "hawkbit.dmf.rabbitmq", name = "enabled", matchIfMissing = true)
@@ -288,7 +292,7 @@ public class AmqpConfiguration {
* for target authentication
* @param artifactManagement
* for artifact URI generation
* @param cache
* @param downloadIdCache
* for download IDs
* @param hostnameResolver
* for resolving the host for downloads
@@ -299,10 +303,10 @@ public class AmqpConfiguration {
@Bean
public AmqpAuthenticationMessageHandler amqpAuthenticationMessageHandler(final RabbitTemplate rabbitTemplate,
final AmqpControllerAuthentication authenticationManager, final ArtifactManagement artifactManagement,
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE) final Cache cache, final HostnameResolver hostnameResolver,
final DownloadIdCache downloadIdCache, final HostnameResolver hostnameResolver,
final ControllerManagement controllerManagement) {
return new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManager, artifactManagement, cache,
hostnameResolver, controllerManagement);
return new AmqpAuthenticationMessageHandler(rabbitTemplate, authenticationManager, artifactManagement,
downloadIdCache, hostnameResolver, controllerManagement);
}
/**
@@ -330,6 +334,23 @@ public class AmqpConfiguration {
return new ConfigurableRabbitListenerContainerFactory(amqpProperties, rabbitConnectionFactory, errorHandler);
}
/**
* create the authentication bean for controller over amqp.
*
* @param systemManagement
* the systemManagement
* @param controllerManagement
* the controllerManagement
* @param tenantConfigurationManagement
* the tenantConfigurationManagement
* @param tenantAware
* the tenantAware
* @param ddiSecruityProperties
* the ddiSecruityProperties
* @param systemSecurityContext
* the systemSecurityContext
* @return the bean
*/
@Bean
@ConditionalOnMissingBean(AmqpControllerAuthentication.class)
public AmqpControllerAuthentication amqpControllerAuthentication(final SystemManagement systemManagement,
@@ -340,13 +361,31 @@ public class AmqpConfiguration {
tenantAware, ddiSecruityProperties, systemSecurityContext);
}
/**
* Create the dispatcher bean.
*
* @param rabbitTemplate
* the rabbitTemplate
* @param amqpSenderService
* to send AMQP message
* @param artifactUrlHandler
* for generating download URLs
* @param systemSecurityContext
* for execution with system permissions
* @param systemManagement
* the systemManagement
* @param targetManagement
* to access target information
* @return the bean
*/
@Bean
@ConditionalOnMissingBean(AmqpMessageDispatcherService.class)
public AmqpMessageDispatcherService amqpMessageDispatcherService(final RabbitTemplate rabbitTemplate,
final AmqpSenderService amqpSenderService, final ArtifactUrlHandler artifactUrlHandler,
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement) {
final SystemSecurityContext systemSecurityContext, final SystemManagement systemManagement,
final TargetManagement targetManagement) {
return new AmqpMessageDispatcherService(rabbitTemplate, amqpSenderService, artifactUrlHandler,
systemSecurityContext, systemManagement);
systemSecurityContext, systemManagement, targetManagement, serviceMatcher);
}
private static Map<String, Object> getTTLMaxArgsAuthenticationQueue() {

View File

@@ -25,18 +25,19 @@ import org.eclipse.hawkbit.dmf.json.model.Artifact;
import org.eclipse.hawkbit.dmf.json.model.ArtifactHash;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.dmf.json.model.SoftwareModule;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.util.IpUtil;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import com.google.common.eventbus.Subscribe;
import org.springframework.cloud.bus.ServiceMatcher;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.context.event.EventListener;
/**
* {@link AmqpMessageDispatcherService} create all outgoing AMQP messages and
@@ -46,13 +47,14 @@ import com.google.common.eventbus.Subscribe;
* assignment.
*
*/
@EventSubscriber
public class AmqpMessageDispatcherService extends BaseAmqpService {
private final ArtifactUrlHandler artifactUrlHandler;
private final AmqpSenderService amqpSenderService;
private final SystemSecurityContext systemSecurityContext;
private final SystemManagement systemManagement;
private final TargetManagement targetManagement;
private final ServiceMatcher serviceMatcher;
/**
* Constructor.
@@ -66,51 +68,68 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* @param systemSecurityContext
* for execution with system permissions
* @param systemManagement
* to access to tenant metadata
* the systemManagement
* @param targetManagement
* to access target information
* @param serviceMatcher
* to check in cluster case if the message is from the same
* cluster node
*/
public AmqpMessageDispatcherService(final RabbitTemplate rabbitTemplate, final AmqpSenderService amqpSenderService,
final ArtifactUrlHandler artifactUrlHandler, final SystemSecurityContext systemSecurityContext,
final SystemManagement systemManagement) {
final SystemManagement systemManagement, final TargetManagement targetManagement,
final ServiceMatcher serviceMatcher) {
super(rabbitTemplate);
this.artifactUrlHandler = artifactUrlHandler;
this.amqpSenderService = amqpSenderService;
this.systemSecurityContext = systemSecurityContext;
this.systemManagement = systemManagement;
this.targetManagement = targetManagement;
this.serviceMatcher = serviceMatcher;
}
/**
* Method to send a message to a RabbitMQ Exchange after the Distribution
* set has been assign to a Target.
*
* @param targetAssignDistributionSetEvent
* @param assignedEvent
* the object to be send.
*/
@Subscribe
public void targetAssignDistributionSet(final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
final URI targetAdress = targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress();
@EventListener(classes = TargetAssignDistributionSetEvent.class)
public void targetAssignDistributionSet(final TargetAssignDistributionSetEvent assignedEvent) {
if (isFromSelf(assignedEvent)) {
return;
}
sendUpdateMessageToTarget(assignedEvent.getTenant(),
targetManagement.findTargetByControllerID(assignedEvent.getControllerId()), assignedEvent.getActionId(),
assignedEvent.getModules());
}
void sendUpdateMessageToTarget(final String tenant, final Target target, final Long actionId,
final Collection<org.eclipse.hawkbit.repository.model.SoftwareModule> modules) {
if (target == null) {
return;
}
final URI targetAdress = target.getTargetInfo().getAddress();
if (!IpUtil.isAmqpUri(targetAdress)) {
return;
}
final String controllerId = targetAssignDistributionSetEvent.getTarget().getControllerId();
final Collection<org.eclipse.hawkbit.repository.model.SoftwareModule> modules = targetAssignDistributionSetEvent
.getSoftwareModules();
final DownloadAndUpdateRequest downloadAndUpdateRequest = new DownloadAndUpdateRequest();
downloadAndUpdateRequest.setActionId(targetAssignDistributionSetEvent.getActionId());
downloadAndUpdateRequest.setActionId(actionId);
final String targetSecurityToken = systemSecurityContext
.runAsSystem(targetAssignDistributionSetEvent.getTarget()::getSecurityToken);
final String targetSecurityToken = systemSecurityContext.runAsSystem(target::getSecurityToken);
downloadAndUpdateRequest.setTargetSecurityToken(targetSecurityToken);
for (final org.eclipse.hawkbit.repository.model.SoftwareModule softwareModule : modules) {
final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(
targetAssignDistributionSetEvent.getTarget(), softwareModule);
final SoftwareModule amqpSoftwareModule = convertToAmqpSoftwareModule(target, softwareModule);
downloadAndUpdateRequest.addSoftwareModule(amqpSoftwareModule);
}
final Message message = getMessageConverter().toMessage(downloadAndUpdateRequest,
createConnectorMessageProperties(targetAssignDistributionSetEvent.getTenant(), controllerId,
EventTopic.DOWNLOAD_AND_INSTALL));
createConnectorMessageProperties(tenant, target.getControllerId(), EventTopic.DOWNLOAD_AND_INSTALL));
amqpSenderService.sendMessage(message, targetAdress);
}
@@ -118,19 +137,29 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
* Method to send a message to a RabbitMQ Exchange after the assignment of
* the Distribution set to a Target has been canceled.
*
* @param cancelTargetAssignmentDistributionSetEvent
* @param cancelEvent
* the object to be send.
*/
@Subscribe
public void targetCancelAssignmentToDistributionSet(
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent) {
final String controllerId = cancelTargetAssignmentDistributionSetEvent.getTarget().getControllerId();
final Long actionId = cancelTargetAssignmentDistributionSetEvent.getActionId();
final Message message = getMessageConverter().toMessage(actionId, createConnectorMessageProperties(
cancelTargetAssignmentDistributionSetEvent.getTenant(), controllerId, EventTopic.CANCEL_DOWNLOAD));
@EventListener(classes = CancelTargetAssignmentEvent.class)
public void targetCancelAssignmentToDistributionSet(final CancelTargetAssignmentEvent cancelEvent) {
if (isFromSelf(cancelEvent)) {
return;
}
amqpSenderService.sendMessage(message,
cancelTargetAssignmentDistributionSetEvent.getTarget().getTargetInfo().getAddress());
sendCancelMessageToTarget(cancelEvent.getTenant(), cancelEvent.getEntity().getControllerId(),
cancelEvent.getActionId(), cancelEvent.getEntity().getTargetInfo().getAddress());
}
private boolean isFromSelf(final RemoteApplicationEvent event) {
return serviceMatcher != null && !serviceMatcher.isFromSelf(event);
}
void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId,
final URI address) {
final Message message = getMessageConverter().toMessage(actionId,
createConnectorMessageProperties(tenant, controllerId, EventTopic.CANCEL_DOWNLOAD));
amqpSenderService.sendMessage(message, address);
}

View File

@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -26,15 +25,11 @@ import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger;
@@ -176,7 +171,7 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
final String replyTo = message.getMessageProperties().getReplyTo();
if (StringUtils.isEmpty(replyTo)) {
logAndThrowMessageError(message, "No ReplyTo was set for the createThing Event.");
logAndThrowMessageError(message, "No ReplyTo was set for the createThing TenantAwareEvent.");
}
final URI amqpUri = IpUtil.createAmqpUri(virtualHost, replyTo);
@@ -187,23 +182,20 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
private void lookIfUpdateAvailable(final Target target) {
final Optional<Action> action = controllerManagement.findOldestActiveActionByTarget(target);
if (!action.isPresent()) {
final Optional<Action> actionOptional = controllerManagement.findOldestActiveActionByTarget(target);
if (!actionOptional.isPresent()) {
return;
}
if (action.get().isCancelingOrCanceled()) {
amqpMessageDispatcherService.targetCancelAssignmentToDistributionSet(
new CancelTargetAssignmentEvent(target, action.get().getId()));
final Action action = actionOptional.get();
if (action.isCancelingOrCanceled()) {
amqpMessageDispatcherService.sendCancelMessageToTarget(target.getTenant(), target.getControllerId(),
action.getId(), target.getTargetInfo().getAddress());
return;
}
final DistributionSet distributionSet = action.get().getDistributionSet();
final List<SoftwareModule> softwareModuleList = controllerManagement
.findSoftwareModulesByDistributionSet(distributionSet);
amqpMessageDispatcherService.targetAssignDistributionSet(new TargetAssignDistributionSetEvent(
target.getOptLockRevision(), target.getTenant(), target, action.get().getId(), softwareModuleList));
amqpMessageDispatcherService.sendUpdateMessageToTarget(action.getTenant(), action.getTarget(), action.getId(),
action.getDistributionSet().getModules());
}
/**
@@ -332,5 +324,4 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
"Cancel recjected message is not allowed, if action is on state: " + action.getStatus());
}
}
}

View File

@@ -21,6 +21,7 @@ import java.net.URL;
import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
@@ -54,7 +55,6 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.cache.Cache;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
@@ -95,7 +95,7 @@ public class AmqpControllerAuthenticationTest {
private SystemManagement systemManagement;
@Mock
private Cache cacheMock;
private DownloadIdCache cacheMock;
@Mock
private HostnameResolver hostnameResolverMock;

View File

@@ -19,9 +19,9 @@ import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.eclipse.hawkbit.api.ArtifactUrl;
import org.eclipse.hawkbit.api.ArtifactUrlHandler;
@@ -31,8 +31,12 @@ import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
import org.eclipse.hawkbit.dmf.json.model.DownloadAndUpdateRequest;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -48,6 +52,7 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.AbstractJavaTypeMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.ActiveProfiles;
@@ -82,11 +87,15 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
private Target testTarget;
@Autowired
protected ActionRepository actionRepository;
@Override
public void before() throws Exception {
super.before();
testTarget = entityFactory.generateTarget(CONTROLLER_ID, TEST_TOKEN);
testTarget.getTargetInfo().setAddress(AMQP_URI.toString());
final Target generateTarget = entityFactory.generateTarget(CONTROLLER_ID, TEST_TOKEN);
generateTarget.getTargetInfo().setAddress(AMQP_URI.toString());
testTarget = targetManagement.createTarget(generateTarget);
this.rabbitTemplate = Mockito.mock(RabbitTemplate.class);
when(rabbitTemplate.getMessageConverter()).thenReturn(new Jackson2JsonMessageConverter());
@@ -105,41 +114,62 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
when(systemManagement.getTenantMetadata()).thenReturn(tenantMetaData);
amqpMessageDispatcherService = new AmqpMessageDispatcherService(rabbitTemplate, senderService,
artifactUrlHandlerMock, systemSecurityContext, systemManagement);
artifactUrlHandlerMock, systemSecurityContext, systemManagement, targetManagement, serviceMatcher);
}
@Test
@Description("Verfies that download and install event with no software modul works")
public void testSendDownloadRequesWithEmptySoftwareModules() {
final Action action = createAction(
testdataFactory.createDistributionSetWithNoSoftwareModules(UUID.randomUUID().toString(), "1.0"));
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, TENANT, testTarget, 1L, Collections.emptyList());
action, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(
targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
assertTrue("No softwaremmodule should be contained in the request",
downloadAndUpdateRequest.getSoftwareModules().isEmpty());
}
private Message getCaptureAdressEvent(final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent) {
final Target target = targetManagement
.findTargetByControllerID(targetAssignDistributionSetEvent.getControllerId());
final Message sendMessage = createArgumentCapture(target.getTargetInfo().getAddress());
return sendMessage;
}
private JpaAction createAction(final DistributionSet testDs) {
final Action action = entityFactory.generateAction();
final JpaAction jpaAction = (JpaAction) action;
action.setDistributionSet(testDs);
action.setTarget(testTarget);
jpaAction.setActionType(ActionType.FORCED);
return actionRepository.save(jpaAction);
}
@Test
@Description("Verfies that download and install event with 3 software moduls and no artifacts works")
public void testSendDownloadRequesWithSoftwareModulesAndNoArtifacts() {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
final DistributionSet createDistributionSet = testdataFactory
.createDistributionSet(UUID.randomUUID().toString());
final Action action = createAction(createDistributionSet);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, TENANT, testTarget, 1L, dsA.getModules());
action, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(
targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
assertEquals("Expecting a size of 3 software modules in the reuqest", 3,
downloadAndUpdateRequest.getSoftwareModules().size());
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
assertThat(createDistributionSet.getModules()).hasSameSizeAs(downloadAndUpdateRequest.getSoftwareModules());
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
for (final org.eclipse.hawkbit.dmf.json.model.SoftwareModule softwareModule : downloadAndUpdateRequest
.getSoftwareModules()) {
assertTrue("Artifact list for softwaremodule should be empty", softwareModule.getArtifacts().isEmpty());
for (final SoftwareModule softwareModule2 : dsA.getModules()) {
for (final SoftwareModule softwareModule2 : action.getDistributionSet().getModules()) {
assertNotNull("Sofware module ID should be set", softwareModule.getModuleId());
if (!softwareModule.getModuleId().equals(softwareModule2.getId())) {
continue;
@@ -157,7 +187,7 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
@Test
@Description("Verfies that download and install event with software moduls and artifacts works")
public void testSendDownloadRequest() {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
final DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final SoftwareModule module = dsA.getModules().iterator().next();
final List<DbArtifact> receivedList = new ArrayList<>();
for (final Artifact artifact : testdataFactory.createArtifacts(module.getId())) {
@@ -165,14 +195,16 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
receivedList.add(new DbArtifact());
}
final Action action = createAction(dsA);
Mockito.when(rabbitTemplate.convertSendAndReceive(any())).thenReturn(receivedList);
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
1L, TENANT, testTarget, 1L, dsA.getModules());
action, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = createArgumentCapture(
targetAssignDistributionSetEvent.getTarget().getTargetInfo().getAddress());
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage);
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
assertEquals("DownloadAndUpdateRequest event should contains 3 software modules", 3,
downloadAndUpdateRequest.getSoftwareModules().size());
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
@@ -201,11 +233,11 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
@Description("Verfies that send cancel event works")
public void testSendCancelRequest() {
final CancelTargetAssignmentEvent cancelTargetAssignmentDistributionSetEvent = new CancelTargetAssignmentEvent(
testTarget, 1L);
testTarget, 1L, serviceMatcher.getServiceId());
amqpMessageDispatcherService
.targetCancelAssignmentToDistributionSet(cancelTargetAssignmentDistributionSetEvent);
final Message sendMessage = createArgumentCapture(
cancelTargetAssignmentDistributionSetEvent.getTarget().getTargetInfo().getAddress());
cancelTargetAssignmentDistributionSetEvent.getEntity().getTargetInfo().getAddress());
assertCancelMessage(sendMessage);
}
@@ -219,12 +251,11 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
}
private DownloadAndUpdateRequest assertDownloadAndInstallMessage(final Message sendMessage) {
private DownloadAndUpdateRequest assertDownloadAndInstallMessage(final Message sendMessage, final Action action) {
assertEventMessage(sendMessage);
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(sendMessage,
DownloadAndUpdateRequest.class);
assertEquals("The action ID of the downloadAndUpdateRequest event shuold be 1",
downloadAndUpdateRequest.getActionId(), Long.valueOf(1));
assertEquals(downloadAndUpdateRequest.getActionId(), action.getId());
assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL,
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
assertEquals("Security token of target", downloadAndUpdateRequest.getTargetSecurityToken(), TEST_TOKEN);

View File

@@ -21,14 +21,14 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Optional;
import org.eclipse.hawkbit.api.HostnameResolver;
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.dmf.amqp.api.EventTopic;
import org.eclipse.hawkbit.dmf.amqp.api.MessageHeaderKey;
import org.eclipse.hawkbit.dmf.amqp.api.MessageType;
@@ -40,17 +40,16 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
@@ -67,7 +66,6 @@ import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.cache.Cache;
import org.springframework.http.HttpStatus;
import ru.yandex.qatools.allure.annotations.Description;
@@ -108,7 +106,7 @@ public class AmqpMessageHandlerServiceTest {
private ArtifactRepository artifactRepositoryMock;
@Mock
private Cache cacheMock;
private DownloadIdCache downloadIdCache;
@Mock
private HostnameResolver hostnameResolverMock;
@@ -120,11 +118,13 @@ public class AmqpMessageHandlerServiceTest {
public void before() throws Exception {
messageConverter = new Jackson2JsonMessageConverter();
when(rabbitTemplate.getMessageConverter()).thenReturn(messageConverter);
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
controllerManagementMock, entityFactoryMock);
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
controllerManagementMock, entityFactoryMock);
amqpAuthenticationMessageHandlerService = new AmqpAuthenticationMessageHandler(rabbitTemplate,
authenticationManagerMock, artifactManagementMock, cacheMock, hostnameResolverMock,
authenticationManagerMock, artifactManagementMock, downloadIdCache, hostnameResolverMock,
controllerManagementMock);
}
@@ -363,10 +363,6 @@ public class AmqpMessageHandlerServiceTest {
// for the test the same action can be used
when(controllerManagementMock.findOldestActiveActionByTarget(Matchers.any())).thenReturn(Optional.of(action));
final List<SoftwareModule> softwareModuleList = createSoftwareModuleList();
when(controllerManagementMock.findSoftwareModulesByDistributionSet(Matchers.any()))
.thenReturn(softwareModuleList);
final MessageProperties messageProperties = createMessageProperties(MessageType.EVENT);
messageProperties.setHeader(MessageHeaderKey.TOPIC, EventTopic.UPDATE_ACTION_STATUS.name());
final ActionUpdateStatus actionUpdateStatus = createActionUpdateStatus(ActionStatus.FINISHED, 23L);
@@ -380,20 +376,19 @@ public class AmqpMessageHandlerServiceTest {
verify(controllerManagementMock).updateTargetStatus(Matchers.any(TargetInfo.class),
Matchers.isNull(TargetUpdateStatus.class), Matchers.isNotNull(Long.class), Matchers.isNull(URI.class));
final ArgumentCaptor<TargetAssignDistributionSetEvent> captorTargetAssignDistributionSetEvent = ArgumentCaptor
.forClass(TargetAssignDistributionSetEvent.class);
verify(amqpMessageDispatcherServiceMock, times(1))
.targetAssignDistributionSet(captorTargetAssignDistributionSetEvent.capture());
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = captorTargetAssignDistributionSetEvent
.getValue();
final ArgumentCaptor<String> tenantCaptor = ArgumentCaptor.forClass(String.class);
final ArgumentCaptor<Target> targetCaptor = ArgumentCaptor.forClass(Target.class);
final ArgumentCaptor<Long> actionIdCaptor = ArgumentCaptor.forClass(Long.class);
assertThat(targetAssignDistributionSetEvent.getTarget().getControllerId()).as("event has wrong controller id")
.isEqualTo("target1");
assertThat(targetAssignDistributionSetEvent.getTarget().getSecurityToken())
.as("targetoken not filled correctly").isEqualTo(action.getTarget().getSecurityToken());
assertThat(targetAssignDistributionSetEvent.getActionId()).as("event has wrong action id").isEqualTo(22L);
assertThat(targetAssignDistributionSetEvent.getSoftwareModules()).as("event has wrong sofware modules")
.isEqualTo(softwareModuleList);
verify(amqpMessageDispatcherServiceMock, times(1)).sendUpdateMessageToTarget(tenantCaptor.capture(),
targetCaptor.capture(), actionIdCaptor.capture(), Matchers.any(Collection.class));
final String tenant = tenantCaptor.getValue();
final String controllerId = targetCaptor.getValue().getControllerId();
final Long actionId = actionIdCaptor.getValue();
assertThat(tenant).as("event has tenant").isEqualTo("DEFAULT");
assertThat(controllerId).as("event has wrong controller id").isEqualTo("target1");
assertThat(actionId).as("event has wrong action id").isEqualTo(22L);
}
@@ -424,14 +419,6 @@ public class AmqpMessageHandlerServiceTest {
return messageProperties;
}
private List<SoftwareModule> createSoftwareModuleList() {
final List<SoftwareModule> softwareModuleList = new ArrayList<>();
final JpaSoftwareModule softwareModule = new JpaSoftwareModule();
softwareModule.setId(777L);
softwareModuleList.add(softwareModule);
return softwareModuleList;
}
private Action createActionWithTarget(final Long targetId, final Status status) throws IllegalAccessException {
// is needed for the creation of targets
initalizeSecurityTokenGenerator();
@@ -440,6 +427,10 @@ public class AmqpMessageHandlerServiceTest {
final JpaAction actionMock = mock(JpaAction.class);
final JpaTarget targetMock = mock(JpaTarget.class);
final TargetInfo targetInfoMock = mock(TargetInfo.class);
final DistributionSet distributionSetMock = mock(DistributionSet.class);
when(distributionSetMock.getId()).thenReturn(1L);
when(actionMock.getDistributionSet()).thenReturn(distributionSetMock);
when(actionMock.getId()).thenReturn(targetId);
when(actionMock.getStatus()).thenReturn(status);
when(actionMock.getTenant()).thenReturn("DEFAULT");

View File

@@ -7,8 +7,6 @@
# http://www.eclipse.org/legal/epl-v10.html
#
# supported: H2, MYSQL
hawkbit.server.database=H2

View File

@@ -25,9 +25,5 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -13,9 +13,9 @@ import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
/**
@@ -31,16 +31,16 @@ public class HttpDownloadAuthenticationFilter extends AbstractPreAuthenticatedPr
private static final Logger LOG = LoggerFactory.getLogger(HttpDownloadAuthenticationFilter.class);
private final Pattern pattern;
private final Cache cache;
private final DownloadIdCache downloadIdCache;
/**
* Constructor.
*
* @param cache
* @param downloadIdCache
* the cache
*/
public HttpDownloadAuthenticationFilter(final Cache cache) {
this.cache = cache;
public HttpDownloadAuthenticationFilter(final DownloadIdCache downloadIdCache) {
this.downloadIdCache = downloadIdCache;
this.pattern = Pattern.compile(REQUEST_ID_REGEX_PATTERN);
}
@@ -56,7 +56,7 @@ public class HttpDownloadAuthenticationFilter extends AbstractPreAuthenticatedPr
if (id == null) {
return null;
}
return cache.get(id).get();
return downloadIdCache.get(id);
}
@Override

View File

@@ -32,11 +32,6 @@
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test -->
<dependency>

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.mgmt.json.model.system;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -21,13 +23,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class MgmtSystemTenantConfigurationValueRequest {
@JsonProperty(required = true)
private Object value;
private Serializable value;
/**
*
* @return the value of the MgmtSystemTenantConfigurationValueRequest
*/
public Object getValue() {
public Serializable getValue() {
return value;
}
@@ -37,7 +39,10 @@ public class MgmtSystemTenantConfigurationValueRequest {
* @param value
*/
public void setValue(final Object value) {
this.value = value;
if (!(value instanceof Serializable)) {
throw new IllegalArgumentException("The value muste be a instance of " + Serializable.class.getName());
}
this.value = (Serializable) value;
}
}

View File

@@ -36,15 +36,14 @@
<artifactId>hawkbit-rest-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- Test -->
<dependency>
@@ -66,22 +65,6 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>

View File

@@ -24,12 +24,12 @@ import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtTargetAssignmentR
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetTypeRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.SoftwareManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;

View File

@@ -28,7 +28,6 @@ import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
@@ -38,6 +37,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;

View File

@@ -10,20 +10,16 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.cache.DownloadType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtDownloadRestApi;
import org.eclipse.hawkbit.rest.util.RequestResponseContextHolder;
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.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -32,6 +28,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import com.google.common.io.ByteStreams;
/**
* A resource for download artifacts.
*
@@ -48,8 +46,7 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi {
private ArtifactRepository artifactRepository;
@Autowired
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
private Cache cache;
private DownloadIdCache downloadIdCache;
@Autowired
private RequestResponseContextHolder requestResponseContextHolder;
@@ -66,13 +63,12 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi {
@ResponseBody
public ResponseEntity<Void> downloadArtifactByDownloadId(@PathVariable("downloadId") final String downloadId) {
try {
final ValueWrapper cacheWrapper = cache.get(downloadId);
if (cacheWrapper == null) {
final DownloadArtifactCache artifactCache = downloadIdCache.get(downloadId);
if (artifactCache == null) {
LOGGER.warn("Download Id {} could not be found", downloadId);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
final DownloadArtifactCache artifactCache = (DownloadArtifactCache) cacheWrapper.get();
DbArtifact artifact = null;
if (DownloadType.BY_SHA1.equals(artifactCache.getDownloadType())) {
@@ -87,14 +83,14 @@ public class MgmtDownloadResource implements MgmtDownloadRestApi {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
try {
IOUtils.copy(artifact.getFileInputStream(),
ByteStreams.copy(artifact.getFileInputStream(),
requestResponseContextHolder.getHttpServletResponse().getOutputStream());
} catch (final IOException e) {
LOGGER.error("Cannot copy streams", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
} finally {
cache.evict(downloadId);
downloadIdCache.evict(downloadId);
}
return ResponseEntity.ok().build();

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
import java.io.Serializable;
import java.util.Map;
import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue;
@@ -116,11 +117,9 @@ public class MgmtSystemResource implements MgmtSystemRestApi {
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
final TenantConfigurationValue<Object> updatedValue = tenantConfigurationManagement
final TenantConfigurationValue<? extends Serializable> updatedValue = tenantConfigurationManagement
.addOrUpdateConfiguration(configKey, configurationValueRest.getValue());
return new ResponseEntity<>(MgmtSystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK);
}
}

View File

@@ -438,7 +438,7 @@ public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest
// perform request
mvc.perform(get("/rest/v1/distributionsets").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[0]._links.self.href",
equalTo("http://localhost/rest/v1/distributionsets/" + set.getId())))
.andExpect(jsonPath("$.content.[0].id", equalTo(set.getId().intValue())))
@@ -469,7 +469,7 @@ public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest
// perform request
mvc.perform(get("/rest/v1/distributionsets/{dsId}", set.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$._links.self.href",
equalTo("http://localhost/rest/v1/distributionsets/" + set.getId())))
.andExpect(jsonPath("$.id", equalTo(set.getId().intValue())))
@@ -522,7 +522,7 @@ public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest
.perform(post("/rest/v1/distributionsets/").content(JsonBuilder.distributionSets(sets))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0]name", equalTo(one.getName())))
.andExpect(jsonPath("[0]description", equalTo(one.getDescription())))
.andExpect(jsonPath("[0]type", equalTo(standardDsType.getKey())))
@@ -757,7 +757,7 @@ public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest
mvc.perform(post("/rest/v1/distributionsets/{dsId}/metadata", testDS.getId())
.contentType(MediaType.APPLICATION_JSON).content(jsonArray.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0]key", equalTo(knownKey1))).andExpect(jsonPath("[0]value", equalTo(knownValue1)))
.andExpect(jsonPath("[1]key", equalTo(knownKey2)))
.andExpect(jsonPath("[1]value", equalTo(knownValue2)));
@@ -786,7 +786,7 @@ public class MgmtDistributionSetResourceTest extends AbstractRestIntegrationTest
mvc.perform(put("/rest/v1/distributionsets/{dsId}/metadata/{key}", testDS.getId(), knownKey)
.contentType(MediaType.APPLICATION_JSON).content(jsonObject.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(updateValue)));
final DistributionSetMetadata assertDS = distributionSetManagement.findOne(testDS, knownKey);

View File

@@ -68,7 +68,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
// generated in this test)
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.key==" + standardDsType.getKey() + ")]$..name",
contains(standardDsType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + standardDsType.getKey() + ")]$..description",
@@ -107,7 +107,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
// descending
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:DESC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[0].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[0].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[0].description", equalTo("Desc1234")))
@@ -121,7 +121,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
// ascending
mvc.perform(get("/rest/v1/distributionsettypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "KEY:ASC")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[3].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[3].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[3].description", equalTo("Desc1234")))
@@ -152,7 +152,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
.perform(post("/rest/v1/distributionsettypes/").content(JsonBuilder.distributionSetTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("TestName1"))).andExpect(jsonPath("[0].key", equalTo("test1")))
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
@@ -258,7 +258,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/mandatorymoduletypes", testType.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo(osType.getName())))
.andExpect(jsonPath("[0].description", equalTo(osType.getDescription())))
.andExpect(jsonPath("[0].maxAssignments", equalTo(1))).andExpect(jsonPath("[0].key", equalTo("os")));
@@ -277,7 +277,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
mvc.perform(get("/rest/v1/distributionsettypes/{dstID}/optionalmoduletypes", testType.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo(appType.getName())))
.andExpect(jsonPath("[0].description", equalTo(appType.getDescription())))
.andExpect(jsonPath("[0].maxAssignments", equalTo(Integer.MAX_VALUE)))
@@ -384,7 +384,7 @@ public class MgmtDistributionSetTypeResourceTest extends AbstractRestIntegration
mvc.perform(get("/rest/v1/distributionsettypes/{dstId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.createdBy", equalTo("uploadTester")))

View File

@@ -11,8 +11,8 @@ package org.eclipse.hawkbit.mgmt.rest.resource;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.DownloadArtifactCache;
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.cache.DownloadType;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.model.Artifact;
@@ -23,8 +23,6 @@ import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.Cache;
import org.springframework.context.annotation.Description;
import ru.yandex.qatools.allure.annotations.Features;
@@ -35,8 +33,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
public class MgmtDownloadResourceTest extends AbstractRestIntegrationTestWithMongoDB {
@Autowired
@Qualifier(CacheConstants.DOWNLOAD_ID_CACHE)
private Cache downloadIdCache;
private DownloadIdCache downloadIdCache;
private final String downloadIdSha1 = "downloadIdSha1";

View File

@@ -125,7 +125,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
@Description("Testing the empty list is returned if no rollout exists")
public void noRolloutReturnsEmptyList() throws Exception {
mvc.perform(get("/rest/v1/rollouts")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(0))).andExpect(jsonPath("$.total", equalTo(0)));
}
@@ -138,7 +138,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
postRollout("rollout2", 5, dsA.getId(), "name==target2");
mvc.perform(get("/rest/v1/rollouts")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)))
.andExpect(jsonPath("content[0].name", equalTo("rollout1")))
.andExpect(jsonPath("content[0].status", equalTo("ready")))
@@ -159,7 +159,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
postRollout("rollout2", 5, dsA.getId(), "name==target2");
mvc.perform(get("/rest/v1/rollouts?limit=1")).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(2)));
}
@@ -177,7 +177,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// retrieve rollout groups from created rollout
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(4))).andExpect(jsonPath("$.total", equalTo(4)))
.andExpect(jsonPath("$.content[0].status", equalTo("ready")))
.andExpect(jsonPath("$.content[1].status", equalTo("ready")))
@@ -202,7 +202,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("running")));
}
@@ -228,7 +228,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("paused")));
}
@@ -258,7 +258,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// check rollout is in running state
mvc.perform(get("/rest/v1/rollouts/{rolloutId}", rollout.getId())).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(rollout.getId().intValue())))
.andExpect(jsonPath("status", equalTo("running")));
}
@@ -320,7 +320,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// (amountTargets / groupSize = 2)
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups?sort=ID:ASC", rollout.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)))
.andExpect(jsonPath("$.content[0].status", equalTo("running")))
.andExpect(jsonPath("$.content[1].status", equalTo("scheduled")));
@@ -344,7 +344,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// retrieve single rollout group with known ID
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}", rollout.getId(), firstGroup.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("id", equalTo(firstGroup.getId().intValue())))
.andExpect(jsonPath("status", equalTo("ready"))).andExpect(jsonPath("name", notNullValue()));
}
@@ -367,7 +367,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// retrieve targets from the first rollout group with known ID
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(),
firstGroup.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(5))).andExpect(jsonPath("$.total", equalTo(5)));
}
@@ -392,7 +392,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(), firstGroup.getId())
.param("q", "controllerId==" + targets.get(0).getControllerId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)));
}
@@ -416,7 +416,7 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// retrieve targets from the first rollout group with known ID
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups/{groupId}/targets", rollout.getId(),
firstGroup.getId())).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(5))).andExpect(jsonPath("$.total", equalTo(5)));
}
@@ -462,18 +462,18 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*2"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
.andExpect(jsonPath("$.content[0].name", equalTo(rollout2.getName())));
mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==rollout*"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(3))).andExpect(jsonPath("$.total", equalTo(3)));
mvc.perform(get("/rest/v1/rollouts").param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==*1"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)));
}
@@ -492,19 +492,19 @@ public class MgmtRolloutResourceTest extends AbstractRestIntegrationTest {
// retrieve rollout groups from created rollout
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(1))).andExpect(jsonPath("$.total", equalTo(1)))
.andExpect(jsonPath("$.content[0].name", equalTo("group-1")));
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group*")).andDo(MockMvcResultPrinter.print())
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(4))).andExpect(jsonPath("$.total", equalTo(4)));
mvc.perform(get("/rest/v1/rollouts/{rolloutId}/deploygroups", rollout.getId())
.param(MgmtRestConstants.REQUEST_PARAMETER_SEARCH, "name==group-1,name==group-2"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content", hasSize(2))).andExpect(jsonPath("$.total", equalTo(2)));
}

View File

@@ -138,7 +138,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.hashes.md5", equalTo(md5sum)))
.andExpect(jsonPath("$.hashes.sha1", equalTo(sha1sum)))
.andExpect(jsonPath("$.size", equalTo(random.length)))
@@ -213,7 +213,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.hashes.md5", equalTo(md5sum)))
.andExpect(jsonPath("$.hashes.sha1", equalTo(sha1sum)))
.andExpect(jsonPath("$.providedFilename", equalTo("orig"))).andExpect(status().isCreated());
@@ -237,7 +237,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(fileUpload("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).file(file)
.param("filename", "customFilename").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.providedFilename", equalTo("customFilename"))).andExpect(status().isCreated());
// check result in db...
@@ -341,7 +341,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
// perform test
mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts/{artId}", sm.getId(), artifact.getId())
.accept(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.id", equalTo(artifact.getId().intValue())))
.andExpect(jsonPath("$.size", equalTo(random.length)))
.andExpect(jsonPath("$.hashes.md5", equalTo(artifact.getMd5Hash())))
@@ -369,7 +369,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(get("/rest/v1/softwaremodules/{smId}/artifacts", sm.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.[0].id", equalTo(artifact.getId().intValue())))
.andExpect(jsonPath("$.[0].size", equalTo(random.length)))
.andExpect(jsonPath("$.[0].hashes.md5", equalTo(artifact.getMd5Hash())))
@@ -538,7 +538,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(get("/rest/v1/softwaremodules").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.id==" + os.getId() + ")].name", contains("name1")))
.andExpect(jsonPath("$.content.[?(@.id==" + os.getId() + ")].version", contains("version1")))
.andExpect(jsonPath("$.content.[?(@.id==" + os.getId() + ")].description", contains("description1")))
@@ -623,7 +623,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
// only by name, only one exists per name
mvc.perform(get("/rest/v1/softwaremodules?q=name==osName1").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.id==" + os1.getId() + ")].name", contains("osName1")))
.andExpect(jsonPath("$.content.[?(@.id==" + os1.getId() + ")].version", contains("1.0.0")))
.andExpect(jsonPath("$.content.[?(@.id==" + os1.getId() + ")].description", contains("description1")))
@@ -634,7 +634,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
// by type, 2 software modules per type exists
mvc.perform(get("/rest/v1/softwaremodules?q=type==application").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.id==" + ah1.getId() + ")].name", contains("appName1")))
.andExpect(jsonPath("$.content.[?(@.id==" + ah1.getId() + ")].version", contains("3.0.0")))
.andExpect(jsonPath("$.content.[?(@.id==" + ah1.getId() + ")].description", contains("description1")))
@@ -650,7 +650,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
// by type and version=2.0.0 -> only one result
mvc.perform(get("/rest/v1/softwaremodules?q=type==runtime;version==2.0.0").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].name", contains("runtimeName1")))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].version", contains("2.0.0")))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].description", contains("description1")))
@@ -660,7 +660,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
// by type and version range >=2.0.0 -> 2 result
mvc.perform(get("/rest/v1/softwaremodules?q=type==runtime;version=ge=2.0.0").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].name", contains("runtimeName1")))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].version", contains("2.0.0")))
.andExpect(jsonPath("$.content.[?(@.id==" + jvm1.getId() + ")].description", contains("description1")))
@@ -691,14 +691,14 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
@Test
@WithUser(principal = "uploadTester", allSpPermissions = true)
@Description("Tests GET request on /rest/v1/softwaremodules/{smId}.")
public void getSoftareModule() throws Exception {
public void getSoftwareModule() throws Exception {
SoftwareModule os = entityFactory.generateSoftwareModule(osType, "name1", "version1", "description1",
"vendor1");
os = softwareManagement.createSoftwareModule(os);
mvc.perform(get("/rest/v1/softwaremodules/{smId}", os.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("name1"))).andExpect(jsonPath("$.version", equalTo("version1")))
.andExpect(jsonPath("$.description", equalTo("description1")))
.andExpect(jsonPath("$.vendor", equalTo("vendor1"))).andExpect(jsonPath("$.type", equalTo("os")))
@@ -718,7 +718,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(get("/rest/v1/softwaremodules/{smId}", jvm.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("name1"))).andExpect(jsonPath("$.version", equalTo("version1")))
.andExpect(jsonPath("$.description", equalTo("description1")))
.andExpect(jsonPath("$.vendor", equalTo("vendor1"))).andExpect(jsonPath("$.type", equalTo("runtime")))
@@ -738,7 +738,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(get("/rest/v1/softwaremodules/{smId}", ah.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("name1"))).andExpect(jsonPath("$.version", equalTo("version1")))
.andExpect(jsonPath("$.description", equalTo("description1")))
.andExpect(jsonPath("$.vendor", equalTo("vendor1")))
@@ -778,7 +778,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
.perform(post("/rest/v1/softwaremodules/").content(JsonBuilder.softwareModules(modules))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("name1")))
.andExpect(jsonPath("[0].version", equalTo("version1")))
.andExpect(jsonPath("[0].description", equalTo("description1")))
@@ -941,7 +941,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(post("/rest/v1/softwaremodules/{swId}/metadata", sm.getId()).contentType(MediaType.APPLICATION_JSON)
.content(jsonArray.toString())).andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0]key", equalTo(knownKey1))).andExpect(jsonPath("[0]value", equalTo(knownValue1)))
.andExpect(jsonPath("[1]key", equalTo(knownKey2)))
.andExpect(jsonPath("[1]value", equalTo(knownValue2)));
@@ -971,7 +971,7 @@ public class MgmtSoftwareModuleResourceTest extends AbstractRestIntegrationTestW
mvc.perform(put("/rest/v1/softwaremodules/{swId}/metadata/{key}", sm.getId(), knownKey)
.contentType(MediaType.APPLICATION_JSON).content(jsonObject.toString()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("key", equalTo(knownKey))).andExpect(jsonPath("value", equalTo(updateValue)));
final SoftwareModuleMetadata assertDS = softwareManagement.findSoftwareModuleMetadata(sm.getId(), knownKey);

View File

@@ -64,7 +64,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].name", contains(osType.getName())))
.andExpect(jsonPath("$.content.[?(@.key==" + osType.getKey() + ")].description",
contains(osType.getDescription())))
@@ -108,7 +108,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:DESC"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[1].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[1].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[1].description", equalTo("Desc1234")))
@@ -124,7 +124,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
mvc.perform(get("/rest/v1/softwaremoduletypes").accept(MediaType.APPLICATION_JSON)
.param(MgmtRestConstants.REQUEST_PARAMETER_SORTING, "MAXASSIGNMENTS:ASC"))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.content.[2].id", equalTo(testType.getId().intValue())))
.andExpect(jsonPath("$.content.[2].name", equalTo("TestName123")))
.andExpect(jsonPath("$.content.[2].description", equalTo("Desc1234")))
@@ -171,7 +171,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
.perform(post("/rest/v1/softwaremoduletypes/").content(JsonBuilder.softwareModuleTypes(types))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("TestName1"))).andExpect(jsonPath("[0].key", equalTo("test1")))
.andExpect(jsonPath("[0].description", equalTo("Desc1")))
.andExpect(jsonPath("[0].createdBy", equalTo("uploadTester")))
@@ -214,7 +214,7 @@ public class MgmtSoftwareModuleTypeResourceTest extends AbstractRestIntegrationT
mvc.perform(get("/rest/v1/softwaremoduletypes/{smtId}", testType.getId()).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.name", equalTo("TestName123")))
.andExpect(jsonPath("$.description", equalTo("Desc1234")))
.andExpect(jsonPath("$.maxAssignments", equalTo(5)))

View File

@@ -8,37 +8,30 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import java.util.*;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.model.*;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.rest.AbstractRestIntegrationTest;
import org.eclipse.hawkbit.rest.exception.MessageNotReadableException;
import org.eclipse.hawkbit.rest.json.model.ExceptionInfo;
import org.eclipse.hawkbit.rest.util.JsonBuilder;
import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter;
import org.json.JSONObject;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import com.jayway.jsonpath.JsonPath;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@@ -51,8 +44,6 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Target Filter Query Resource")
public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTest {
private static final String TARGET_DESCRIPTION_TEST = "created in test";
private static final String JSON_PATH_ROOT = "$";
// fields, attributes
@@ -75,17 +66,16 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
private static final String JSON_PATH_QUERY = JSON_PATH_ROOT + JSON_PATH_FIELD_QUERY;
private static final String JSON_PATH_AUTO_ASSIGN_DS = JSON_PATH_ROOT + JSON_PATH_FIELD_AUTO_ASSIGN_DS;
@Test
@Description("Ensures that deletion is executed if permitted.")
public void deleteTargetFilterQueryReturnsOK() throws Exception {
final String filterName = "filter_01";
TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name=test_01");
final TargetFilterQuery filterQuery = createSingleTargetFilterQuery(filterName, "name=test_01");
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + filterQuery.getId()))
.andExpect(status().isOk());
TargetFilterQuery tfq = targetFilterQueryManagement.findTargetFilterQueryById(filterQuery.getId());
final TargetFilterQuery tfq = targetFilterQueryManagement.findTargetFilterQueryById(filterQuery.getId());
assertThat(tfq).isNull();
}
@@ -116,7 +106,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
final String body = new JSONObject().put("query", filterQuery2).toString();
// prepare
TargetFilterQuery tfq = createSingleTargetFilterQuery(filterName, filterQuery);
final TargetFilterQuery tfq = createSingleTargetFilterQuery(filterName, filterQuery);
mvc.perform(put(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()).content(body)
.contentType(MediaType.APPLICATION_JSON)).andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -124,7 +114,7 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
.andExpect(jsonPath("$.query", equalTo(filterQuery2)))
.andExpect(jsonPath("$.name", equalTo(filterName)));
TargetFilterQuery tfqCheck = targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId());
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId());
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery2);
assertThat(tfqCheck.getName()).isEqualTo(filterName);
}
@@ -149,12 +139,11 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
.andExpect(jsonPath("$.query", equalTo(filterQuery)))
.andExpect(jsonPath("$.name", equalTo(filterName2)));
TargetFilterQuery tfqCheck = targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId());
final TargetFilterQuery tfqCheck = targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId());
assertThat(tfqCheck.getQuery()).isEqualTo(filterQuery);
assertThat(tfqCheck.getName()).isEqualTo(filterName2);
}
@Test
@Description("Ensures that request returns list of filters in defined format.")
public void getTargetFilterQueryWithoutAdditionalRequestParameters() throws Exception {
@@ -250,7 +239,8 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
final String knownQuery = "name=test01";
final String knownName = "someName";
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
final String hrefPrefix = "http://localhost"+MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING+"/" + tfq.getId();
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
// test
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -302,13 +292,15 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
final DistributionSet set = testdataFactory.createDistributionSet("one");
final TargetFilterQuery tfq = createSingleTargetFilterQuery(knownName, knownQuery);
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"+tfq.getId()+"/autoAssignDS")
mvc.perform(post(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS")
.content("{\"id\":" + set.getId() + "}").contentType(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
assertThat(targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId()).getAutoAssignDistributionSet()).isEqualTo(set);
assertThat(targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId()).getAutoAssignDistributionSet())
.isEqualTo(set);
final String hrefPrefix = "http://localhost"+MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING+"/" + tfq.getId();
final String hrefPrefix = "http://localhost" + MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"
+ tfq.getId();
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId()))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
@@ -336,20 +328,18 @@ public class MgmtTargetFilterQueryResourceTest extends AbstractRestIntegrationTe
assertThat(targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId()).getAutoAssignDistributionSet())
.isEqualTo(set);
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"+tfq.getId()+"/autoAssignDS"))
.andExpect(status().isOk())
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(dsName)));
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isOk()).andExpect(jsonPath(JSON_PATH_NAME, equalTo(dsName)));
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"+tfq.getId()+"/autoAssignDS"))
mvc.perform(delete(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isNoContent());
assertThat(targetFilterQueryManagement.findTargetFilterQueryById(tfq.getId()).getAutoAssignDistributionSet())
.isNull();
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/"+tfq.getId()+"/autoAssignDS"))
mvc.perform(get(MgmtRestConstants.TARGET_FILTER_V1_REQUEST_MAPPING + "/" + tfq.getId() + "/autoAssignDS"))
.andExpect(status().isNoContent());
}
private TargetFilterQuery createSingleTargetFilterQuery(final String name, final String query) {

View File

@@ -735,7 +735,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
.perform(post("/rest/v1/targets/").content(JsonBuilder.targets(targets, true))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andDo(MockMvcResultPrinter.print()).andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("[0].name", equalTo("testname1")))
.andExpect(jsonPath("[0].controllerId", equalTo("id1")))
.andExpect(jsonPath("[0].description", equalTo("testid1")))

View File

@@ -7,6 +7,9 @@
# http://www.eclipse.org/legal/epl-v10.html
#
logging.level.=INFO
logging.level.org.eclipse.persistence=ERROR
# supported: H2, MYSQL
hawkbit.server.database=H2

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.eclipse.hawkbit.eventbus.DeadEventListener" level="WARN" />
<Logger name="org.springframework.boot.actuate.audit.listener.AuditListener" level="WARN" />
<Logger name="org.hibernate.validator.internal.util.Version" level="WARN" />
<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN" />
<Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN" />
<Logger name="org.apache.tomcat.jdbc.pool.ConnectionPool" level="DEBUG" />
<Logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR" />
<!-- <Logger name="org.eclipse.hawkbit.rest.util.MockMvcResultPrinter" level="DEBUG" /> -->
<!-- Security Log with hints on potential attacks -->
<logger name="server-security" level="INFO" />
<Root level="INFO">
<appender-ref ref="CONSOLE" />
</Root>
</configuration>

View File

@@ -8,7 +8,8 @@
http://www.eclipse.org/legal/epl-v10.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
@@ -36,6 +37,10 @@
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<!-- Optional -->
<dependency>

View File

@@ -16,7 +16,7 @@ import java.util.Optional;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
@@ -25,7 +25,6 @@ import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
@@ -34,8 +33,6 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.security.access.prepost.PreAuthorize;
import com.google.common.eventbus.EventBus;
/**
* Service layer for all operations of the DDI API (with access permissions only
* for the controller).
@@ -59,7 +56,7 @@ public interface ControllerManagement {
Action addCancelActionStatus(@NotNull ActionStatus actionStatus);
/**
* Sends the download progress and notifies the {@link EventBus} with a
* Sends the download progress and notifies the event publisher with a
* {@link DownloadProgressEvent}.
*
* @param statusId
@@ -148,19 +145,6 @@ public interface ControllerManagement {
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
Target findOrRegisterTargetIfItDoesNotexist(@NotEmpty String controllerId, URI address);
/**
* Retrieves all {@link SoftwareModule}s which are assigned to the given
* {@link DistributionSet}.
*
* @param distributionSet
* the distribution set which should be assigned to the returned
* {@link SoftwareModule}s
* @return a list of {@link SoftwareModule}s assigned to given
* {@code distributionSet}
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
List<SoftwareModule> findSoftwareModulesByDistributionSet(@NotNull DistributionSet distributionSet);
/**
* Retrieves last {@link Action} for a download of an artifact of given
* module and target.

View File

@@ -24,6 +24,7 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.ActionWithStatusCount;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;

View File

@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.repository;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.repository;
import java.io.Serializable;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
@@ -40,7 +42,8 @@ public interface TenantConfigurationManagement {
* if the property cannot be converted to the given
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
<T> TenantConfigurationValue<T> addOrUpdateConfiguration(TenantConfigurationKey configurationKey, T value);
<T extends Serializable> TenantConfigurationValue<T> addOrUpdateConfiguration(
TenantConfigurationKey configurationKey, T value);
/**
* Build the tenant configuration by the given key
@@ -55,8 +58,8 @@ public interface TenantConfigurationManagement {
* or returns the tenant configuration value
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
<T> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(TenantConfigurationKey configurationKey,
Class<T> propertyType, TenantConfiguration tenantConfiguration);
<T extends Serializable> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
TenantConfigurationKey configurationKey, Class<T> propertyType, TenantConfiguration tenantConfiguration);
/**
* Deletes a specific configuration for the current tenant. Does nothing in
@@ -87,7 +90,7 @@ public interface TenantConfigurationManagement {
* {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
<T> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey);
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey);
/**
* Retrieves a configuration value from the e.g. tenant overwritten
@@ -113,7 +116,7 @@ public interface TenantConfigurationManagement {
* {@code propertyType}
*/
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
<T> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey,
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey,
Class<T> propertyType);
/**

View File

@@ -6,7 +6,7 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.eventbus.event;
package org.eclipse.hawkbit.repository.event;
/**
* Events to be published to refresh data on UI.

View File

@@ -6,22 +6,18 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.cache;
package org.eclipse.hawkbit.repository.event;
/**
* Cache Constants.
*
*
* An event declaration which holds an revision for each event so consumers have
* the chance to know if they might already retrieved a newer event.
*
*/
public final class CacheConstants {
@FunctionalInterface
public interface TenantAwareEvent {
/**
* Constant for download cache id.
* @return the tenant of the event.
*/
public static final String DOWNLOAD_ID_CACHE = "DowonloadIdCache";
private CacheConstants() {
}
String getTenant();
}

View File

@@ -0,0 +1,40 @@
/**
* 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.event.remote;
import org.eclipse.hawkbit.repository.model.DistributionSet;
/**
* Defines the remote event for deletion of {@link DistributionSet}.
*/
public class DistributionSetDeletedEvent extends RemoteIdEvent {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public DistributionSetDeletedEvent() {
// for serialization libs like jackson
}
/**
* Constructor.
*
* @param tenant
* the tenant
* @param entityId
* the entity id
* @param applicationId
* the origin application id
*/
public DistributionSetDeletedEvent(final String tenant, final Long entityId, final String applicationId) {
super(entityId, tenant, applicationId);
}
}

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