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

@@ -10,6 +10,8 @@ package org.eclipse.hawkbit;
import java.util.Map;
import javax.persistence.EntityManager;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.DeploymentManagement;
@@ -26,6 +28,8 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.TenantStatsManagement;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder;
import org.eclipse.hawkbit.repository.jpa.JpaArtifactManagement;
import org.eclipse.hawkbit.repository.jpa.JpaControllerManagement;
import org.eclipse.hawkbit.repository.jpa.JpaDeploymentManagement;
@@ -45,20 +49,19 @@ import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler;
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignChecker;
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignScheduler;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle;
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -77,7 +80,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import com.google.common.collect.Maps;
import com.google.common.eventbus.EventBus;
/**
* General configuration for hawkBit's Repository.
@@ -93,8 +95,6 @@ import com.google.common.eventbus.EventBus;
@EnableScheduling
@EntityScan("org.eclipse.hawkbit.repository.jpa.model")
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Autowired
private EventBus eventBus;
@Bean
@ConditionalOnMissingBean
@@ -163,14 +163,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return EntityInterceptorHolder.getInstance();
}
/**
* @return the singleton instance of the {@link CacheManagerHolder}
*/
@Bean
public CacheManagerHolder cacheManagerHolder() {
return CacheManagerHolder.getInstance();
}
/**
*
* @return the singleton instance of the
@@ -273,9 +265,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Bean
@ConditionalOnMissingBean
public TenantStatsManagement tenantStatsManagement() {
final TenantStatsManagement mgmt = new JpaTenantStatsManagement();
eventBus.register(mgmt);
return mgmt;
return new JpaTenantStatsManagement();
}
/**
@@ -400,6 +390,32 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return new JpaEntityFactory();
}
/**
* {@link EventEntityManagerHolder} bean.
*
* @return a new {@link EventEntityManagerHolder}
*/
@Bean
@ConditionalOnMissingBean
public EventEntityManagerHolder eventEntityManagerHolder() {
return EventEntityManagerHolder.getInstance();
}
/**
* {@link EventEntityManager} bean.
*
* @param aware
* the tenant aware
* @param entityManager
* the entitymanager
* @return a new {@link EventEntityManager}
*/
@Bean
@ConditionalOnMissingBean
public EventEntityManager eventEntityManager(final TenantAware aware, final EntityManager entityManager) {
return new JpaEventEntityManager(aware, entityManager);
}
/**
* {@link AutoAssignChecker} bean.
*
@@ -415,9 +431,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
*/
@Bean
@ConditionalOnMissingBean
public AutoAssignChecker autoAssignChecker(TargetFilterQueryManagement targetFilterQueryManagement,
TargetManagement targetManagement, DeploymentManagement deploymentManagement,
PlatformTransactionManager transactionManager) {
public AutoAssignChecker autoAssignChecker(final TargetFilterQueryManagement targetFilterQueryManagement,
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
final PlatformTransactionManager transactionManager) {
return new AutoAssignChecker(targetFilterQueryManagement, targetManagement, deploymentManagement,
transactionManager);
}
@@ -437,8 +453,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
*/
@Bean
@ConditionalOnMissingBean
public AutoAssignScheduler autoAssignScheduler(TenantAware tenantAware, SystemManagement systemManagement,
SystemSecurityContext systemSecurityContext, AutoAssignChecker autoAssignChecker) {
public AutoAssignScheduler autoAssignScheduler(final TenantAware tenantAware,
final SystemManagement systemManagement, final SystemSecurityContext systemSecurityContext,
final AutoAssignChecker autoAssignChecker) {
return new AutoAssignScheduler(tenantAware, systemManagement, systemSecurityContext, autoAssignChecker);
}
}

View File

@@ -9,7 +9,6 @@
package org.eclipse.hawkbit.repository.jpa;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -24,10 +23,10 @@ import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.RepositoryProperties;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
import org.eclipse.hawkbit.repository.jpa.cache.CacheWriteNotify;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_;
@@ -41,7 +40,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;
@@ -49,10 +47,13 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
@@ -86,9 +87,6 @@ public class JpaControllerManagement implements ControllerManagement {
@Autowired
private TargetInfoRepository targetInfoRepository;
@Autowired
private SoftwareModuleRepository softwareModuleRepository;
@Autowired
private ActionStatusRepository actionStatusRepository;
@@ -105,11 +103,17 @@ public class JpaControllerManagement implements ControllerManagement {
private TenantConfigurationManagement tenantConfigurationManagement;
@Autowired
private CacheWriteNotify cacheWriteNotify;
private TenantAware tenantAware;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private ApplicationContext applicationContext;
@Override
public String getPollingTime() {
final TenantConfigurationKey configurationKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
@@ -178,12 +182,6 @@ public class JpaControllerManagement implements ControllerManagement {
return actionRepository.findFirstByTargetAndActive(new Sort(Direction.ASC, "id"), (JpaTarget) target, true);
}
@Override
public List<SoftwareModule> findSoftwareModulesByDistributionSet(final DistributionSet distributionSet) {
return Collections
.unmodifiableList(softwareModuleRepository.findByAssignedTo((JpaDistributionSet) distributionSet));
}
@Override
public Action findActionWithDetails(final Long actionId) {
return actionRepository.findById(actionId);
@@ -480,7 +478,8 @@ public class JpaControllerManagement implements ControllerManagement {
@Override
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
final Long shippedBytesOverall) {
cacheWriteNotify.downloadProgress(statusId, requestedBytes, shippedBytesSinceLast, shippedBytesOverall);
eventPublisher.publishEvent(new DownloadProgressEvent(tenantAware.getCurrentTenant(), shippedBytesSinceLast,
applicationContext.getId()));
}
@Override

View File

@@ -30,12 +30,10 @@ import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.ActionFields;
import org.eclipse.hawkbit.repository.DeploymentManagement;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.eventbus.event.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
@@ -51,11 +49,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
@@ -63,20 +59,22 @@ 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;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.hibernate.validator.constraints.NotEmpty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -90,7 +88,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
/**
* JPA implementation for {@link DeploymentManagement}.
@@ -110,9 +107,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
@Autowired
private DistributionSetRepository distributoinSetRepository;
@Autowired
private SoftwareModuleRepository softwareModuleRepository;
@Autowired
private TargetRepository targetRepository;
@@ -129,14 +123,14 @@ public class JpaDeploymentManagement implements DeploymentManagement {
private AuditorAware<String> auditorProvider;
@Autowired
private EventBus eventBus;
private ApplicationEventPublisher eventPublisher;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private AfterTransactionCommitExecutor afterCommit;
@Autowired
private SystemSecurityContext systemSecurityContext;
@Autowired
private VirtualPropertyReplacer virtualPropertyReplacer;
@@ -316,21 +310,18 @@ public class JpaDeploymentManagement implements DeploymentManagement {
LOG.debug("assignDistribution({}) finished {}", set, result);
final List<JpaSoftwareModule> softwareModules = softwareModuleRepository.findByAssignedTo(set);
// detaching as it is not necessary to persist the set itself
entityManager.detach(set);
sendDistributionSetAssignmentEvent(targets, targetIdsCancellList, targetIdsToActions, softwareModules);
sendDistributionSetAssignmentEvent(targets, targetIdsCancellList, targetIdsToActions);
return result;
}
private void sendDistributionSetAssignmentEvent(final List<JpaTarget> targets, final Set<Long> targetIdsCancellList,
final Map<String, JpaAction> targetIdsToActions, final List<JpaSoftwareModule> softwareModules) {
final Map<String, JpaAction> targetIdsToActions) {
targets.stream().filter(t -> !!!targetIdsCancellList.contains(t.getId()))
.forEach(t -> assignDistributionSetEvent(t, targetIdsToActions.get(t.getControllerId()).getId(),
softwareModules));
.forEach(t -> assignDistributionSetEvent(targetIdsToActions.get(t.getControllerId())));
}
private static JpaAction createTargetAction(final Map<String, TargetWithActionType> targetsWithActionMap,
@@ -349,17 +340,11 @@ public class JpaDeploymentManagement implements DeploymentManagement {
return actionForTarget;
}
private void assignDistributionSetEvent(final JpaTarget target, final Long actionId,
final List<JpaSoftwareModule> modules) {
((JpaTargetInfo) target.getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING);
private void assignDistributionSetEvent(final Action action) {
((JpaTargetInfo) action.getTarget().getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING);
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<SoftwareModule> softwareModules = (Collection) modules;
afterCommit.afterCommit(() -> {
eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo()));
eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), target,
actionId, softwareModules));
});
afterCommit.afterCommit(() -> eventPublisher
.publishEvent(new TargetAssignDistributionSetEvent(action, applicationContext.getId())));
}
/**
@@ -431,7 +416,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
/**
* Sends the {@link CancelTargetAssignmentEvent} for a specific target to
* the {@link EventBus}.
* the eventPublisher.
*
* @param target
* the Target which has been assigned to a distribution set
@@ -439,7 +424,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
* the action id of the assignment
*/
private void cancelAssignDistributionSetEvent(final Target target, final Long actionId) {
afterCommit.afterCommit(() -> eventBus.post(new CancelTargetAssignmentEvent(target, actionId)));
afterCommit.afterCommit(() -> eventPublisher
.publishEvent(new CancelTargetAssignmentEvent(target, actionId, applicationContext.getId())));
}
@Override
@@ -534,11 +520,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
// in case we canceled an action before for this target, then don't fire
// assignment event
if (!overrideObsoleteUpdateActions.contains(savedAction.getId())) {
final List<JpaSoftwareModule> softwareModules = softwareModuleRepository
.findByAssignedTo((JpaDistributionSet) savedAction.getDistributionSet());
// send distribution set assignment event
assignDistributionSetEvent((JpaTarget) savedAction.getTarget(), savedAction.getId(), softwareModules);
assignDistributionSetEvent(savedAction);
}
return savedAction;
}

View File

@@ -27,8 +27,7 @@ import org.eclipse.hawkbit.repository.DistributionSetMetadataFields;
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TagManagement;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagAssigmentResultEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityLockedException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
@@ -57,6 +56,8 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -68,7 +69,6 @@ import org.springframework.validation.annotation.Validated;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
/**
* JPA implementation of {@link DistributionSetManagement}.
@@ -103,7 +103,10 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private ActionRepository actionRepository;
@Autowired
private EventBus eventBus;
private ApplicationEventPublisher eventPublisher;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private AfterTransactionCommitExecutor afterCommit;
@@ -146,18 +149,13 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
}
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), 0,
toBeChangedDSs.size(), Collections.emptyList(),
Collections.unmodifiableList(distributionSetRepository.save(toBeChangedDSs)), myTag,
tenantAware.getCurrentTenant());
Collections.unmodifiableList(distributionSetRepository.save(toBeChangedDSs)), myTag);
} else {
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), toBeChangedDSs.size(),
0, Collections.unmodifiableList(distributionSetRepository.save(toBeChangedDSs)),
Collections.emptyList(), myTag, tenantAware.getCurrentTenant());
Collections.emptyList(), myTag);
}
final DistributionSetTagAssignmentResult resultAssignment = result;
afterCommit.afterCommit(() -> eventBus
.post(new DistributionSetTagAssigmentResultEvent(resultAssignment, tenantAware.getCurrentTenant())));
// no reason to persist the tag
entityManager.detach(myTag);
return result;
@@ -187,7 +185,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
// soft delete assigned
if (!assigned.isEmpty()) {
Long[] dsIds = assigned.toArray(new Long[assigned.size()]);
final Long[] dsIds = assigned.toArray(new Long[assigned.size()]);
distributionSetRepository.deleteDistributionSet(dsIds);
targetFilterQueryRepository.unsetAutoAssignDistributionSet(dsIds);
}
@@ -203,8 +201,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
distributionSetRepository.deleteByIdIn(toHardDelete);
}
Arrays.stream(distributionSetIDs)
.forEach(dsId -> eventBus.post(new DistributionDeletedEvent(tenantAware.getCurrentTenant(), dsId)));
Arrays.stream(distributionSetIDs).forEach(dsId -> eventPublisher.publishEvent(
new DistributionSetDeletedEvent(tenantAware.getCurrentTenant(), dsId, applicationContext.getId())));
}
@Override
@@ -710,16 +708,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
allDs.forEach(ds -> ds.addTag(tag));
final List<DistributionSet> save = Collections.unmodifiableList(distributionSetRepository.save(allDs));
afterCommit.afterCommit(() -> {
final DistributionSetTagAssignmentResult result = new DistributionSetTagAssignmentResult(0, save.size(), 0,
save, Collections.emptyList(), tag, tenantAware.getCurrentTenant());
eventBus.post(new DistributionSetTagAssigmentResultEvent(result, tenantAware.getCurrentTenant()));
});
return save;
return Collections.unmodifiableList(distributionSetRepository.save(allDs));
}
@Override

View File

@@ -44,7 +44,6 @@ import org.eclipse.hawkbit.repository.report.model.SeriesTime;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -81,7 +80,6 @@ public class JpaReportManagement implements ReportManagement {
private TenantAware tenantAware;
@Override
@Cacheable("targetStatus")
public DataReportSeries<TargetUpdateStatus> targetStatus() {
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
@@ -106,7 +104,44 @@ public class JpaReportManagement implements ReportManagement {
}
@Override
@Cacheable("distributionUsageAssigned")
public DataReportSeries<SeriesTime> targetsLastPoll() {
final LocalDateTime now = LocalDateTime.now();
final LocalDateTime beforeHour = now.minusHours(1);
final LocalDateTime beforeDay = now.minusDays(1);
final LocalDateTime beforeWeek = now.minusWeeks(1);
final LocalDateTime beforeMonth = now.minusMonths(1);
final LocalDateTime beforeYear = now.minusYears(1);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final List<DataReportSeriesItem<SeriesTime>> resultList = new ArrayList<>();
// hours
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.HOUR,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, beforeHour, now)).getSingleResult()));
// days
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.DAY, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeDay, beforeHour)).getSingleResult()));
// weeks
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.WEEK, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeWeek, beforeDay)).getSingleResult()));
// months
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MONTH, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeMonth, beforeWeek)).getSingleResult()));
// years
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.YEAR, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeYear, beforeMonth)).getSingleResult()));
// years
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MORE_THAN_YEAR,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, beforeYear)).getSingleResult()));
// never
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.NEVER,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, null)).getSingleResult()));
return new DataReportSeries<>("TargetLastPoll", resultList);
}
@Override
public List<InnerOuterDataReportSeries<String>> distributionUsageAssigned(final int topXEntries) {
// top X entries distribution usage
@@ -132,7 +167,6 @@ public class JpaReportManagement implements ReportManagement {
}
@Override
@Cacheable("distributionUsageInstalled")
public List<InnerOuterDataReportSeries<String>> distributionUsageInstalled(final int topXEntries) {
// top X entries distribution usage
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
@@ -157,7 +191,6 @@ public class JpaReportManagement implements ReportManagement {
}
@Override
@Cacheable("targetsCreatedOverPeriod")
public <T extends Serializable> DataReportSeries<T> targetsCreatedOverPeriod(final DateType<T> dateType,
final LocalDateTime from, final LocalDateTime to) {
final Query createNativeQuery = entityManager
@@ -208,7 +241,6 @@ public class JpaReportManagement implements ReportManagement {
}
@Override
@Cacheable("feedbackReceivedOverTime")
public <T extends Serializable> DataReportSeries<T> feedbackReceivedOverTime(final DateType<T> dateType,
final LocalDateTime from, final LocalDateTime to) {
final Query createNativeQuery = entityManager
@@ -223,47 +255,8 @@ public class JpaReportManagement implements ReportManagement {
return new DataReportSeries<>("FeedbackRecieved", reportItems);
}
@Override
@Cacheable("targetsLastPoll")
public DataReportSeries<SeriesTime> targetsLastPoll() {
final LocalDateTime now = LocalDateTime.now();
final LocalDateTime beforeHour = now.minusHours(1);
final LocalDateTime beforeDay = now.minusDays(1);
final LocalDateTime beforeWeek = now.minusWeeks(1);
final LocalDateTime beforeMonth = now.minusMonths(1);
final LocalDateTime beforeYear = now.minusYears(1);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final List<DataReportSeriesItem<SeriesTime>> resultList = new ArrayList<>();
// hours
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.HOUR,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, beforeHour, now)).getSingleResult()));
// days
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.DAY, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeDay, beforeHour)).getSingleResult()));
// weeks
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.WEEK, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeWeek, beforeDay)).getSingleResult()));
// months
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MONTH, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeMonth, beforeWeek)).getSingleResult()));
// years
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.YEAR, entityManager
.createQuery(createCountSelectTargetsLastPoll(cb, beforeYear, beforeMonth)).getSingleResult()));
// years
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MORE_THAN_YEAR,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, beforeYear)).getSingleResult()));
// never
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.NEVER,
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, null)).getSingleResult()));
return new DataReportSeries<>("TargetLastPoll", resultList);
}
private CriteriaQuery<Long> createCountSelectTargetsLastPoll(final CriteriaBuilder cb, final LocalDateTime from,
final LocalDateTime to) {
private static CriteriaQuery<Long> createCountSelectTargetsLastPoll(final CriteriaBuilder cb,
final LocalDateTime from, final LocalDateTime to) {
Long start = null;
Long end = null;
@@ -289,8 +282,8 @@ public class JpaReportManagement implements ReportManagement {
return countSelect;
}
private List<InnerOuterDataReportSeries<String>> mapDistirbutionUsageResultToDataReport(final int topXEntries,
final List<Object[]> resultListTop) {
private static List<InnerOuterDataReportSeries<String>> mapDistirbutionUsageResultToDataReport(
final int topXEntries, final List<Object[]> resultListTop) {
final List<InnerOuterDataReportSeries<String>> innerOuterReport = new ArrayList<>();
final Map<DSName, InnerOuter> map = new LinkedHashMap<>();

View File

@@ -24,8 +24,8 @@ import org.eclipse.hawkbit.repository.RolloutFields;
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
import org.eclipse.hawkbit.repository.RolloutManagement;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
import org.eclipse.hawkbit.repository.jpa.cache.CacheWriteNotify;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
@@ -54,6 +54,7 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -110,15 +111,15 @@ public class JpaRolloutManagement implements RolloutManagement {
@Autowired
private ApplicationContext context;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private NoCountPagingRepository criteriaNoCountDao;
@Autowired
private PlatformTransactionManager txManager;
@Autowired
private CacheWriteNotify cacheWriteNotify;
@Autowired
private VirtualPropertyReplacer virtualPropertyReplacer;
@@ -249,13 +250,6 @@ public class JpaRolloutManagement implements RolloutManagement {
int groupIndex = 0;
final Long totalCount = savedRollout.getTotalTargets();
final int groupSize = (int) Math.ceil((double) totalCount / (double) amountOfGroups);
// validate if the amount of groups that will be created are the amount
// of groups that the client what's to have created.
int amountGroupValidated = amountOfGroups;
final int amountGroupCreation = (int) (Math.ceil((double) totalCount / (double) groupSize));
if (amountGroupCreation == (amountOfGroups - 1)) {
amountGroupValidated--;
}
RolloutGroup lastSavedGroup = null;
while (pageIndex < totalCount) {
groupIndex++;
@@ -282,11 +276,11 @@ public class JpaRolloutManagement implements RolloutManagement {
targetGroup
.forEach(target -> rolloutTargetGroupRepository.save(new RolloutTargetGroup(savedGroup, target)));
cacheWriteNotify.rolloutGroupCreated(groupIndex, savedRollout.getId(), savedGroup.getId(),
amountGroupValidated, groupIndex);
eventPublisher.publishEvent(new RolloutGroupCreatedEvent(group, context.getId()));
pageIndex += groupSize;
}
savedRollout.setRolloutGroupsCreated(groupIndex);
savedRollout.setStatus(RolloutStatus.READY);
return rolloutRepository.save(savedRollout);
}

View File

@@ -598,12 +598,10 @@ public class JpaSoftwareManagement implements SoftwareManagement {
@Override
public List<SoftwareModuleMetadata> findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) {
return Collections
.unmodifiableList(softwareModuleMetadataRepository
.findAll((Specification<JpaSoftwareModuleMetadata>) (root, query,
cb) -> cb.and(cb.equal(
root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id),
softwareModuleId))));
return Collections.unmodifiableList(softwareModuleMetadataRepository
.findAll((Specification<JpaSoftwareModuleMetadata>) (root, query, cb) -> cb
.and(cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id),
softwareModuleId))));
}
@Override

View File

@@ -17,12 +17,12 @@ import java.util.List;
import org.eclipse.hawkbit.repository.TagFields;
import org.eclipse.hawkbit.repository.TagManagement;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagUpdateEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetTagUpdateEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdateEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdateEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
@@ -33,8 +33,11 @@ import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -44,8 +47,6 @@ import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.google.common.eventbus.EventBus;
/**
* JP>A implementation of {@link TagManagement}.
*
@@ -67,14 +68,17 @@ public class JpaTagManagement implements TagManagement {
private DistributionSetRepository distributionSetRepository;
@Autowired
private EventBus eventBus;
private ApplicationEventPublisher eventPublisher;
@Autowired
private TenantAware tenantAware;
private ApplicationContext applicationContext;
@Autowired
private AfterTransactionCommitExecutor afterCommit;
@Autowired
private TenantAware tenantAware;
@Autowired
private VirtualPropertyReplacer virtualPropertyReplacer;
@@ -96,7 +100,8 @@ public class JpaTagManagement implements TagManagement {
final TargetTag save = targetTagRepository.save((JpaTargetTag) targetTag);
afterCommit.afterCommit(() -> eventBus.post(new TargetTagCreatedEvent(save)));
afterCommit.afterCommit(
() -> eventPublisher.publishEvent(new TargetTagCreatedEvent(save, applicationContext.getId())));
return save;
}
@@ -115,7 +120,8 @@ public class JpaTagManagement implements TagManagement {
});
final List<TargetTag> save = Collections.unmodifiableList(targetTagRepository.save(targetTags));
afterCommit.afterCommit(() -> save.forEach(tag -> eventBus.post(new TargetTagCreatedEvent(tag))));
afterCommit.afterCommit(() -> save.forEach(
tag -> eventPublisher.publishEvent(new TargetTagCreatedEvent(tag, applicationContext.getId()))));
return save;
}
@@ -137,7 +143,8 @@ public class JpaTagManagement implements TagManagement {
// finally delete the tag itself
targetTagRepository.deleteByName(targetTagName);
afterCommit.afterCommit(() -> eventBus.post(new TargetTagDeletedEvent(tag)));
afterCommit.afterCommit(() -> eventPublisher.publishEvent(
new TargetTagDeletedEvent(tenantAware.getCurrentTenant(), tag.getId(), applicationContext.getId())));
}
@@ -174,7 +181,8 @@ public class JpaTagManagement implements TagManagement {
checkNotNull(targetTag.getName());
checkNotNull(targetTag.getId());
final TargetTag save = targetTagRepository.save((JpaTargetTag) targetTag);
afterCommit.afterCommit(() -> eventBus.post(new TargetTagUpdateEvent(save)));
afterCommit.afterCommit(() -> eventPublisher
.publishEvent(new TargetTagUpdateEvent(save, EventPublisherHolder.getInstance().getApplicationId())));
return save;
}
@@ -197,7 +205,8 @@ public class JpaTagManagement implements TagManagement {
final DistributionSetTag save = distributionSetTagRepository.save((JpaDistributionSetTag) distributionSetTag);
afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagCreatedEvent(save)));
afterCommit.afterCommit(() -> eventPublisher
.publishEvent(new DistributionSetTagCreatedEvent(save, applicationContext.getId())));
return save;
}
@@ -216,8 +225,8 @@ public class JpaTagManagement implements TagManagement {
}
final List<DistributionSetTag> save = Collections
.unmodifiableList(distributionSetTagRepository.save(distributionSetTags));
afterCommit.afterCommit(() -> save.forEach(tag -> eventBus.post(new DistributionSetTagCreatedEvent(tag))));
afterCommit.afterCommit(() -> save.forEach(tag -> eventPublisher
.publishEvent(new DistributionSetTagCreatedEvent(tag, applicationContext.getId()))));
return save;
}
@@ -238,7 +247,9 @@ public class JpaTagManagement implements TagManagement {
distributionSetTagRepository.deleteByName(tagName);
afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagDeletedEvent(tag)));
afterCommit.afterCommit(
() -> eventPublisher.publishEvent(new DistributionSetTagDeletedEvent(tenantAware.getCurrentTenant(),
tag.getId(), applicationContext.getId())));
}
@Override
@@ -248,7 +259,8 @@ public class JpaTagManagement implements TagManagement {
checkNotNull(distributionSetTag.getName());
checkNotNull(distributionSetTag.getId());
final DistributionSetTag save = distributionSetTagRepository.save((JpaDistributionSetTag) distributionSetTag);
afterCommit.afterCommit(() -> eventBus.post(new DistributionSetTagUpdateEvent(save)));
afterCommit.afterCommit(() -> eventPublisher.publishEvent(
new DistributionSetTagUpdateEvent(save, EventPublisherHolder.getInstance().getApplicationId())));
return save;
}

View File

@@ -16,7 +16,6 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PreDestroy;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
@@ -32,8 +31,8 @@ import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetTagAssigmentResultEvent;
import org.eclipse.hawkbit.repository.TimestampCalculator;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
@@ -56,6 +55,8 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -71,7 +72,6 @@ import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
/**
* JPA implementation of {@link TargetManagement}.
@@ -97,7 +97,10 @@ public class JpaTargetManagement implements TargetManagement {
private NoCountPagingRepository criteriaNoCountDao;
@Autowired
private EventBus eventBus;
private ApplicationEventPublisher eventPublisher;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private TenantAware tenantAware;
@@ -218,7 +221,8 @@ public class JpaTargetManagement implements TargetManagement {
public void deleteTargets(final Collection<Long> targetIDs) {
targetRepository.deleteByIdIn(targetIDs);
targetIDs.forEach(targetId -> eventBus.post(new TargetDeletedEvent(tenantAware.getCurrentTenant(), targetId)));
targetIDs.forEach(targetId -> eventPublisher.publishEvent(
new TargetDeletedEvent(tenantAware.getCurrentTenant(), targetId, applicationContext.getId())));
}
@Override
@@ -368,8 +372,6 @@ public class JpaTargetManagement implements TargetManagement {
final TargetTagAssignmentResult result = new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(),
Collections.emptyList(), alreadyAssignedTargets, tag);
afterCommit.afterCommit(
() -> eventBus.post(new TargetTagAssigmentResultEvent(result, tenantAware.getCurrentTenant())));
return result;
}
@@ -380,9 +382,6 @@ public class JpaTargetManagement implements TargetManagement {
allTargets.size(), 0, Collections.unmodifiableList(targetRepository.save(allTargets)),
Collections.emptyList(), tag);
afterCommit.afterCommit(
() -> eventBus.post(new TargetTagAssigmentResultEvent(result, tenantAware.getCurrentTenant())));
// no reason to persist the tag
entityManager.detach(tag);
return result;
@@ -396,15 +395,7 @@ public class JpaTargetManagement implements TargetManagement {
.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(controllerIds));
allTargets.forEach(target -> target.addTag(tag));
final List<Target> save = Collections.unmodifiableList(targetRepository.save(allTargets));
afterCommit.afterCommit(() -> {
final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, save.size(), 0, save,
Collections.emptyList(), tag);
eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult, tenantAware.getCurrentTenant()));
});
return save;
return Collections.unmodifiableList(targetRepository.save(allTargets));
}
private List<Target> unAssignTag(final Collection<Target> targets, final TargetTag tag) {
@@ -413,13 +404,7 @@ public class JpaTargetManagement implements TargetManagement {
toUnassign.forEach(target -> target.removeTag(tag));
final List<Target> save = Collections.unmodifiableList(targetRepository.save(toUnassign));
afterCommit.afterCommit(() -> {
final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, 0, save.size(),
Collections.emptyList(), save, tag);
eventBus.post(new TargetTagAssigmentResultEvent(assigmentResult, tenantAware.getCurrentTenant()));
});
return save;
return Collections.unmodifiableList(targetRepository.save(toUnassign));
}
@Override
@@ -612,11 +597,6 @@ public class JpaTargetManagement implements TargetManagement {
return countByCriteriaAPI(specList);
}
@PreDestroy
void destroy() {
eventBus.unregister(this);
}
@Override
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)

View File

@@ -8,6 +8,8 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import java.io.Serializable;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration;
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
@@ -46,8 +48,8 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan
@Override
@Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
public <T> TenantConfigurationValue<T> getConfigurationValue(final TenantConfigurationKey configurationKey,
final Class<T> propertyType) {
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(
final TenantConfigurationKey configurationKey, final Class<T> propertyType) {
validateTenantConfigurationDataType(configurationKey, propertyType);
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
@@ -75,7 +77,7 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan
}
@Override
public <T> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
public <T extends Serializable> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
final TenantConfigurationKey configurationKey, final Class<T> propertyType,
final TenantConfiguration tenantConfiguration) {
if (tenantConfiguration != null) {
@@ -95,7 +97,8 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan
}
@Override
public <T> TenantConfigurationValue<T> getConfigurationValue(final TenantConfigurationKey configurationKey) {
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(
final TenantConfigurationKey configurationKey) {
return getConfigurationValue(configurationKey, configurationKey.getDataType());
}
@@ -122,8 +125,8 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan
@CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Modifying
public <T> TenantConfigurationValue<T> addOrUpdateConfiguration(final TenantConfigurationKey configurationKey,
final T value) {
public <T extends Serializable> TenantConfigurationValue<T> addOrUpdateConfiguration(
final TenantConfigurationKey configurationKey, final T value) {
if (!configurationKey.getDataType().isAssignableFrom(value.getClass())) {
throw new TenantConfigurationValidatorException(String.format(

View File

@@ -20,6 +20,7 @@ import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -43,7 +44,7 @@ public interface RolloutRepository
* @return the count of the updated rows. Zero if no row has been updated
*/
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
@Query("UPDATE JpaRollout r SET r.lastCheck = :lastCheck WHERE r.lastCheck < (:lastCheck - :delay) AND r.status=:status")
int updateLastCheck(@Param("lastCheck") final long lastCheck, @Param("delay") final long delay,
@Param("status") final RolloutStatus status);

View File

@@ -89,13 +89,13 @@ public interface SoftwareModuleRepository
/**
*
*
* @param set
* @param setId
* to search for
* @return all {@link SoftwareModule}s that are assigned to given
* {@link DistributionSet}
*/
@EntityGraph(value = "SoftwareModule.artifacts", type = EntityGraphType.LOAD)
List<JpaSoftwareModule> findByAssignedTo(JpaDistributionSet set);
List<JpaSoftwareModule> findByAssignedToId(Long setId);
/**
* @param pageable

View File

@@ -15,7 +15,6 @@ import javax.persistence.Entity;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
@@ -53,6 +52,5 @@ public interface TargetInfoRepository {
*
* @return persisted or updated {@link Entity}
*/
@CacheEvict(value = { "targetStatus", "distributionUsageInstalled", "targetsLastPoll" }, allEntries = true)
<S extends JpaTargetInfo> S save(S entity);
}

View File

@@ -41,9 +41,6 @@ import com.google.common.collect.Maps;
* {@link Aspect} catches persistence exceptions and wraps them to custom
* specific exceptions Additionally it checks and prevents access to certain
* packages. Logging aspect which logs the call stack
*
*
*
*/
@Aspect
public class ExceptionMappingAspectHandler implements Ordered {

View File

@@ -1,41 +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.repository.jpa.cache;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener;
import org.springframework.cache.CacheManager;
import org.springframework.data.annotation.Transient;
/**
* Marks an field within a JPA entity as transient and this field should be
* loaded from a configured {@link CacheManager} by using the JPA entity
* listeners.
*
*
*
* @see CacheFieldEntityListener
*/
@Target({ FIELD })
@Retention(RUNTIME)
@Transient
public @interface CacheField {
/**
* @return the cache key name for this cacheable field which is used to
* store the value.
*/
String key();
}

View File

@@ -1,56 +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.repository.jpa.cache;
import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener;
/**
* RepositoryConstants for cache keys used in multiple classes.
*
*
*
*
* @see CacheFieldEntityListener
* @see CacheWriteNotify
* @see CacheField
*
*/
public final class CacheKeys {
/**
* The cache key name for the {@link UpdateActionStatus} download progress
* event.
*/
public static final String DOWNLOAD_PROGRESS_PERCENT = "download.progress.percent";
public static final String ROLLOUT_GROUP_CREATED = "rollout.group.created";
public static final String ROLLOUT_GROUP_TOTAL = "rollout.group.total";
/**
* utility class only private constructor.
*/
private CacheKeys() {
}
/**
* calculates the cache key for a specific entity. The cache key must be
* different for each different identifiable entity by its ID.
*
* @param entityId
* the ID of the entity to build the specific cache key for this
* entity
* @param cacheKey
* the cache key for the field to be cached
* @return the combined cache key based on the given {@code entityId} and
* {@code cacheKey}
*/
public static String entitySpecificCacheKey(final String entityId, final String cacheKey) {
return entityId + "." + cacheKey;
}
}

View File

@@ -1,143 +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.repository.jpa.cache;
import java.math.RoundingMode;
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.EventBus;
import com.google.common.math.DoubleMath;
/**
* An service which combines the functionality for functional use cases to write
* into the cache an notify the writing to the cache to the {@link EventBus}.
*
*
*
*/
@Service
public class CacheWriteNotify {
private static final int DOWNLOAD_PROGRESS_MAX = 100;
@Autowired
private CacheManager cacheManager;
@Autowired
private EventBus eventBus;
@Autowired
private TenantAware tenantAware;
/**
* writes the download progress into the cache
* {@link CacheKeys#DOWNLOAD_PROGRESS_PERCENT} and notifies the
* {@link EventBus} with a {@link DownloadProgressEvent}.
*
* @param statusId
* the ID of the {@link ActionStatus}
* @param requestedBytes
* requested bytes of the request
* @param shippedBytesSinceLast
* since last event
* @param shippedBytesOverall
* for the download request
*/
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
final Long shippedBytesOverall) {
final Cache cache = cacheManager.getCache(ActionStatus.class.getName());
final String cacheKey = CacheKeys.entitySpecificCacheKey(String.valueOf(statusId),
CacheKeys.DOWNLOAD_PROGRESS_PERCENT);
final int progressPercent = DoubleMath.roundToInt(shippedBytesOverall * 100.0 / requestedBytes,
RoundingMode.DOWN);
if (progressPercent < DOWNLOAD_PROGRESS_MAX) {
cache.put(cacheKey, progressPercent);
} else {
// in case we reached progress 100 delete the cache value again
// because otherwise he will
// keep there forever
cache.evict(cacheKey);
}
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, requestedBytes,
shippedBytesSinceLast, shippedBytesOverall));
}
/**
* Writes the {@link CacheKeys#ROLLOUT_GROUP_CREATED} and
* {@link CacheKeys#ROLLOUT_GROUP_TOTAL} into the cache and notfies the
* {@link EventBus} with a {@link RolloutGroupCreatedEvent}.
*
* @param revision
* the revision of the event
* @param rolloutId
* the ID of the rollout the group has been created
* @param rolloutGroupId
* the ID of the rollout group which has been created
* @param totalRolloutGroup
* the total number of rollout groups for this rollout
* @param createdRolloutGroup
* the number of already created groups of the rollout
*/
public void rolloutGroupCreated(final long revision, final Long rolloutId, final Long rolloutGroupId,
final int totalRolloutGroup, final int createdRolloutGroup) {
final Cache cache = cacheManager.getCache(Rollout.class.getName());
final String cacheKeyGroupTotal = CacheKeys.entitySpecificCacheKey(String.valueOf(rolloutId),
CacheKeys.ROLLOUT_GROUP_TOTAL);
final String cacheKeyGroupCreated = CacheKeys.entitySpecificCacheKey(String.valueOf(rolloutId),
CacheKeys.ROLLOUT_GROUP_CREATED);
if (createdRolloutGroup < totalRolloutGroup) {
cache.put(cacheKeyGroupTotal, totalRolloutGroup);
cache.put(cacheKeyGroupCreated, createdRolloutGroup);
} else {
// in case we reached progress 100 delete the cache value again
// because otherwise he will keep there forever
cache.evict(cacheKeyGroupTotal);
cache.evict(cacheKeyGroupCreated);
}
eventBus.post(new RolloutGroupCreatedEvent(tenantAware.getCurrentTenant(), revision, rolloutId, rolloutGroupId,
totalRolloutGroup, createdRolloutGroup));
}
/**
* @param cacheManager
* the cacheManager to set
*/
void setCacheManager(final CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
/**
* @param eventBus
* the eventBus to set
*/
void setEventBus(final EventBus eventBus) {
this.eventBus = eventBus;
}
/**
* @param tenantAware
* the tenantAware to set
*/
void setTenantAware(final TenantAware tenantAware) {
this.tenantAware = tenantAware;
}
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.event;
import javax.persistence.EntityManager;
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
/**
* A TenantAwareEvent entity manager, which loads an entity by id and type for
* remote events.
*/
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
public class JpaEventEntityManager implements EventEntityManager {
private final TenantAware tenantAware;
private final EntityManager entityManager;
/**
* Constructor.
*
* @param tenantAware
* the tenant aware
* @param entityManager
* the entity manager
*/
public JpaEventEntityManager(final TenantAware tenantAware, final EntityManager entityManager) {
this.tenantAware = tenantAware;
this.entityManager = entityManager;
}
@Override
public <E extends TenantAwareBaseEntity> E findEntity(final String tenant, final Long id,
final Class<E> entityType) {
return tenantAware.runAsTenant(tenant, () -> entityManager.find(entityType, id));
}
}

View File

@@ -1,193 +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.repository.jpa.eventbus;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.hawkbit.eventbus.EventSubscriber;
import org.eclipse.hawkbit.eventbus.event.Event;
import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* Collects and merges fine grained events to more generic events and push them
* in a fixed delay on the events bus. This helps for code which are not
* interested in all fine grained events, e.g. UI code. The UI code is not
* interested in handling the flood of events, so collecting the events and
* merge them to one event together and post them in a fixed interval is easier
* to consume e.g. for push notifications on UI.
*
*/
@EventSubscriber
@Service
public class EventMerger {
private static final Set<RolloutEventKey> rolloutEvents = ConcurrentHashMap.newKeySet();
private static final Set<RolloutEventKey> rolloutGroupEvents = ConcurrentHashMap.newKeySet();
@Autowired
private EventBus eventBus;
/**
* Checks if there are events to publish in the fixed interval.
*/
@Scheduled(initialDelay = 10000, fixedDelay = 2000)
public void rolloutEventScheduler() {
final Iterator<RolloutEventKey> rolloutIterator = rolloutEvents.iterator();
while (rolloutIterator.hasNext()) {
final RolloutEventKey eventKey = rolloutIterator.next();
eventBus.post(new RolloutChangeEvent(1, eventKey.tenant, eventKey.rolloutId));
rolloutIterator.remove();
}
final Iterator<RolloutEventKey> rolloutGroupIterator = rolloutGroupEvents.iterator();
while (rolloutGroupIterator.hasNext()) {
final RolloutEventKey eventKey = rolloutGroupIterator.next();
eventBus.post(new RolloutGroupChangeEvent(1, eventKey.tenant, eventKey.rolloutId, eventKey.rolloutGroupId));
rolloutGroupIterator.remove();
}
}
/**
* Called by the event bus to retrieve all necessary events to collect and
* merge.
*
* @param event
* the event on the event bus
*/
@Subscribe
@AllowConcurrentEvents
public void onEvent(final Event event) {
Long rolloutId = null;
Long rolloutGroupId = null;
if (event instanceof ActionCreatedEvent) {
rolloutId = getRolloutId(((ActionCreatedEvent) event).getEntity().getRollout());
rolloutGroupId = getRolloutGroupId(((ActionCreatedEvent) event).getEntity().getRolloutGroup());
} else if (event instanceof ActionPropertyChangeEvent) {
rolloutId = getRolloutId(((ActionPropertyChangeEvent) event).getEntity().getRollout());
rolloutGroupId = getRolloutGroupId(((ActionPropertyChangeEvent) event).getEntity().getRolloutGroup());
} else if (event instanceof RolloutPropertyChangeEvent) {
rolloutId = ((RolloutPropertyChangeEvent) event).getEntity().getId();
} else if (event instanceof RolloutGroupCreatedEvent) {
rolloutId = ((RolloutGroupCreatedEvent) event).getRolloutId();
rolloutGroupId = ((RolloutGroupCreatedEvent) event).getRolloutGroupId();
} else if (event instanceof RolloutGroupPropertyChangeEvent) {
final RolloutGroup rolloutGroup = ((RolloutGroupPropertyChangeEvent) event).getEntity();
rolloutId = rolloutGroup.getRollout().getId();
rolloutGroupId = rolloutGroup.getId();
}
if (rolloutId != null) {
rolloutEvents.add(new RolloutEventKey(rolloutId, event.getTenant()));
if (rolloutGroupId != null) {
rolloutGroupEvents.add(new RolloutEventKey(rolloutId, rolloutGroupId, event.getTenant()));
}
}
}
private Long getRolloutGroupId(final RolloutGroup rolloutGroup) {
if (rolloutGroup != null) {
return rolloutGroup.getId();
}
return null;
}
private Long getRolloutId(final Rollout rollout) {
if (rollout != null) {
return rollout.getId();
}
return null;
}
/**
* The rollout key in the concurrent set to be hold.
*
* @author Michael Hirsch
*
*/
private static final class RolloutEventKey {
private final Long rolloutId;
private final String tenant;
private final Long rolloutGroupId;
private RolloutEventKey(final Long rolloutId, final Long rolloutGroupId, final String tenant) {
this.rolloutGroupId = rolloutGroupId;
this.rolloutId = rolloutId;
this.tenant = tenant;
}
private RolloutEventKey(final Long rolloutId, final String tenant) {
this(rolloutId, null, tenant);
}
@Override
public int hashCode() {// NOSONAR - as this is generated
final int prime = 31;
int result = 1;
result = prime * result + ((rolloutGroupId == null) ? 0 : rolloutGroupId.hashCode());
result = prime * result + ((rolloutId == null) ? 0 : rolloutId.hashCode());
result = prime * result + ((tenant == null) ? 0 : tenant.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {// NOSONAR - as this is
// generated
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final RolloutEventKey other = (RolloutEventKey) obj;
if (rolloutGroupId == null) {
if (other.rolloutGroupId != null) {
return false;
}
} else if (!rolloutGroupId.equals(other.rolloutGroupId)) {
return false;
}
if (rolloutId == null) {
if (other.rolloutId != null) {
return false;
}
} else if (!rolloutId.equals(other.rolloutId)) {
return false;
}
if (tenant == null) {
if (other.tenant != null) {
return false;
}
} else if (!tenant.equals(other.tenant)) {
return false;
}
return true;
}
}
}

View File

@@ -31,8 +31,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@MappedSuperclass
@Access(AccessType.FIELD)
@EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class,
EntityInterceptorListener.class })
@EntityListeners({ AuditingEntityListener.class, EntityPropertyChangeListener.class, EntityInterceptorListener.class })
public abstract class AbstractJpaBaseEntity implements BaseEntity {
private static final long serialVersionUID = 1L;

View File

@@ -14,9 +14,9 @@ import javax.persistence.PrePersist;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
import org.eclipse.persistence.annotations.Multitenant;
import org.eclipse.persistence.annotations.MultitenantType;
import org.eclipse.persistence.annotations.TenantDiscriminatorColumn;

View File

@@ -1,123 +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.repository.jpa.model;
import java.io.Serializable;
import java.lang.reflect.Field;
import javax.persistence.PostLoad;
import javax.persistence.PostRemove;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
import org.springframework.hateoas.Identifiable;
/**
* An JPA entity listener which enriches the JPA entity fields which are
* annotated with {@link CacheField} with values from the {@link CacheManager}.
* Only JPA entities which are implementing {@link Identifiable} can be handled
* by this entity listener cause the cache keys are calculated with the ID of
* the entity.
*
*
*
*
*/
public class CacheFieldEntityListener {
private static final Logger LOGGER = LoggerFactory.getLogger(CacheFieldEntityListener.class);
/**
* enriches the JPA entities after loading the entity from the SQL database.
*
* @param target
* the target which has been loaded from the database
*/
@PostLoad
public void postLoad(final Object target) {
if (target instanceof Identifiable) {
final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager();
@SuppressWarnings("rawtypes")
final String id = ((Identifiable) target).getId().toString();
final Class<? extends Object> type = target.getClass();
findCacheFields(type, id, (field, cacheKey, id1) -> {
final Cache cache = cacheManager.getCache(type.getName());
final ValueWrapper valueWrapper = cache.get(CacheKeys.entitySpecificCacheKey(id1.toString(), cacheKey));
if (valueWrapper != null && valueWrapper.get() != null) {
FieldUtils.writeField(field, target, valueWrapper.get(), true);
}
});
}
}
/**
* deletes the associated cache fields from the cache when deleted the
* entity from the database.
*
* @param target
* the entity which has been deleted
*/
@PostRemove
public void postDelete(final Object target) {
if (target instanceof Identifiable) {
final CacheManager cacheManager = CacheManagerHolder.getInstance().getCacheManager();
@SuppressWarnings("rawtypes")
final String id = ((Identifiable) target).getId().toString();
final Class<? extends Object> type = target.getClass();
findCacheFields(type, id, (field, cacheKey, id1) -> {
final Cache cache = cacheManager.getCache(type.getName());
cache.evict(CacheKeys.entitySpecificCacheKey(id1.toString(), cacheKey));
});
}
}
private void findCacheFields(final Class<? extends Object> type, final Serializable id,
final CacheFieldCallback callback) {
final Field[] declaredFields = type.getDeclaredFields();
for (final Field field : declaredFields) {
if (field.getAnnotation(CacheField.class) != null) {
try {
final CacheField annotation = field.getAnnotation(CacheField.class);
callback.fromCache(field, annotation.key(), id);
} catch (final IllegalAccessException e) {
LOGGER.error("cannot access the field {} for the entity {}, ignoring the cacheable field", field,
type, e);
}
}
}
}
@FunctionalInterface
private interface CacheFieldCallback {
/**
* callback methods which is called by the
* {@link CacheFieldEntityListener#findCacheFields(Class, Serializable, CacheFieldCallback)}
* in case a field is annotated with {@link CacheField}.
*
* @param field
* the field which is annotaed with {@link CacheField}
* @param cacheKey
* the configured cache key in the annotation
* {@link CacheField#key()}
* @param id
* the ID of the entity
* @throws IllegalAccessException
* in case the field cannot be accessed
*/
void fromCache(final Field field, final String cacheKey, Serializable id) throws IllegalAccessException;
}
}

View File

@@ -30,16 +30,15 @@ import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
@@ -187,13 +186,14 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Override
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(this));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new ActionCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus()
.post(new ActionPropertyChangeEvent(this, EntityPropertyChangeHelper.getChangeSet(descriptorEvent)));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new ActionUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}
@Override

View File

@@ -25,11 +25,8 @@ import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -72,13 +69,6 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
@Column(name = "detail_message", length = 512)
private List<String> messages;
/**
* Note: filled only in {@link Status#DOWNLOAD}.
*/
@Transient
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
private short downloadProgressPercent;
/**
* Creates a new {@link ActionStatus} object.
*
@@ -121,11 +111,6 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
// JPA default constructor.
}
@Override
public short getDownloadProgressPercent() {
return downloadProgressPercent;
}
@Override
public Long getOccurredAt() {
return occurredAt;

View File

@@ -12,9 +12,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@@ -34,14 +34,11 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent.PropertyChange;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdateEvent;
import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException;
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
@@ -52,8 +49,13 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
import org.eclipse.persistence.sessions.changesets.ObjectChangeSet;
import org.springframework.context.ApplicationEvent;
/**
* Jpa implementation of {@link DistributionSet}.
@@ -347,27 +349,40 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(this));
publishEventWithEventPublisher(
new DistributionSetCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
final Map<String, PropertyChange> changeSet = EntityPropertyChangeHelper.getChangeSet(descriptorEvent);
EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(this));
publishEventWithEventPublisher(
new DistributionSetUpdateEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
if (changeSet.containsKey(DELETED_PROPERTY)) {
final Boolean newDeleted = (Boolean) changeSet.get(DELETED_PROPERTY).getNewValue();
if (newDeleted) {
EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId()));
}
if (isSoftDeleted(descriptorEvent)) {
publishEventWithEventPublisher(new DistributionSetDeletedEvent(getTenant(), getId(),
EventPublisherHolder.getInstance().getApplicationId()));
}
}
@Override
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId()));
publishEventWithEventPublisher(new DistributionSetDeletedEvent(getTenant(), getId(),
EventPublisherHolder.getInstance().getApplicationId()));
}
private static void publishEventWithEventPublisher(final ApplicationEvent event) {
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(event);
}
private static boolean isSoftDeleted(final DescriptorEvent event) {
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
}
}

View File

@@ -28,12 +28,9 @@ import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
@@ -86,12 +83,7 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
@Column(name = "total_targets")
private long totalTargets;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL)
private int rolloutGroupsTotal;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED)
@Column(name = "rollout_groups_created")
private int rolloutGroupsCreated;
@Transient
@@ -172,14 +164,6 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
this.totalTargets = totalTargets;
}
public int getRolloutGroupsTotal() {
return rolloutGroupsTotal;
}
public void setRolloutGroupsTotal(final int rolloutGroupsTotal) {
this.rolloutGroupsTotal = rolloutGroupsTotal;
}
@Override
public int getRolloutGroupsCreated() {
return rolloutGroupsCreated;
@@ -215,8 +199,8 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus()
.post(new RolloutPropertyChangeEvent(this, EntityPropertyChangeHelper.getChangeSet(descriptorEvent)));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new RolloutUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}

View File

@@ -26,12 +26,11 @@ import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupUpdatedEvent;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.persistence.descriptors.DescriptorEvent;
/**
@@ -256,8 +255,9 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(
new RolloutGroupPropertyChangeEvent(this, EntityPropertyChangeHelper.getChangeSet(descriptorEvent)));
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(new RolloutGroupUpdatedEvent(this,
EventPublisherHolder.getInstance().getApplicationId()));
}
@Override

View File

@@ -37,10 +37,9 @@ import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
@@ -49,6 +48,7 @@ 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.TargetTag;
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.springframework.data.domain.Persistable;
@@ -278,16 +278,19 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
@Override
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(this));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new TargetCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(this));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new TargetUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
}
@Override
public void fireDeleteEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new TargetDeletedEvent(getTenant(), getId()));
EventPublisherHolder.getInstance().getEventPublisher()
.publishEvent(new TargetDeletedEvent(getTenant(), getId(), EventPublisherHolder.getInstance().getApplicationId()));
}
}

View File

@@ -40,16 +40,16 @@ import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.PollStatus;
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.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.eclipse.persistence.annotations.CascadeOnDelete;
@@ -338,7 +338,8 @@ public class JpaTargetInfo implements Persistable<Long>, TargetInfo, EventAwareE
@Override
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(this));
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
new TargetUpdatedEvent(this.getTarget(), EventPublisherHolder.getInstance().getApplicationId()));
}
@Override

View File

@@ -1,58 +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.repository.jpa.model.helper;
import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
/**
* A singleton bean which holds the {@link CacheManager} to have to the cache
* manager in beans not instantiated by spring e.g. JPA entities or
* {@link CacheFieldEntityListener} which cannot be autowired.
*
*
*
*/
public final class CacheManagerHolder {
private static final CacheManagerHolder SINGLETON = new CacheManagerHolder();
@Autowired
private CacheManager cacheManager;
private CacheManagerHolder() {
}
/**
* @return the cache manager holder singleton instance
*/
public static CacheManagerHolder getInstance() {
return SINGLETON;
}
/**
* @return the cacheManager
*/
public CacheManager getCacheManager() {
return cacheManager;
}
/**
* Normally not used when using spring-boot then the cachemanager is
* autowired to the CacheManagerHolder, but for testing purposes.
*
* @param cacheManager
* the cache manager to set for the cache manager holder.
*/
public void setCacheManager(final CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
}

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.repository.jpa.model.helper;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent.PropertyChange;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
/**
* Helper class to get the change set for the property changes in the Entity.
*
*/
public final class EntityPropertyChangeHelper {
private EntityPropertyChangeHelper() {
// noop
}
/**
* To get the map of entity property change set
*
* @param clazz
* @param event
* @return the map of the changeSet
*/
public static Map<String, PropertyChange> getChangeSet(final DescriptorEvent event) {
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
return changeSet.getChanges().stream().filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record)
.collect(Collectors.toMap(record -> record.getAttribute(),
record -> new PropertyChange(record.getOldValue(), record.getNewValue())));
}
}

View File

@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.FieldValueConverter;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.SimpleTypeConverter;

View File

@@ -0,0 +1,27 @@
alter table sp_ds_module drop constraint fk_ds_module_ds;
alter table sp_ds_module
add constraint fk_ds_module_ds
foreign key (ds_id)
references sp_distribution_set (id)
on delete cascade;
alter table sp_ds_module drop constraint fk_ds_module_module;
alter table sp_ds_module
add constraint fk_ds_module_module
foreign key (module_id)
references sp_base_software_module (id)
on delete cascade;
alter table sp_external_artifact drop constraint fk_external_assigned_sm;
alter table sp_external_artifact
add constraint fk_external_assigned_sm
foreign key (software_module)
references sp_base_software_module (id)
on delete cascade;
alter table sp_artifact drop constraint fk_assigned_sm;
alter table sp_artifact
add constraint fk_assigned_sm
foreign key (software_module)
references sp_base_software_module (id)
on delete cascade;

View File

@@ -0,0 +1,2 @@
ALTER TABLE sp_rollout ADD column rollout_groups_created BIGINT;

View File

@@ -0,0 +1,27 @@
alter table sp_ds_module drop FOREIGN KEY fk_ds_module_ds;
alter table sp_ds_module
add constraint fk_ds_module_ds
foreign key (ds_id)
references sp_distribution_set (id)
on delete cascade;
alter table sp_ds_module drop FOREIGN KEY fk_ds_module_module;
alter table sp_ds_module
add constraint fk_ds_module_module
foreign key (module_id)
references sp_base_software_module (id)
on delete cascade;
alter table sp_external_artifact drop FOREIGN KEY fk_external_assigned_sm;
alter table sp_external_artifact
add constraint fk_external_assigned_sm
foreign key (software_module)
references sp_base_software_module (id)
on delete cascade;
alter table sp_artifact drop FOREIGN KEY fk_assigned_sm;
alter table sp_artifact
add constraint fk_assigned_sm
foreign key (software_module)
references sp_base_software_module (id)
on delete cascade;

View File

@@ -0,0 +1,2 @@
ALTER TABLE sp_rollout ADD column rollout_groups_created BIGINT;

View File

@@ -0,0 +1,91 @@
/**
* 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 static org.junit.Assert.fail;
import java.util.Map;
import org.apache.commons.lang3.ClassUtils;
import org.eclipse.hawkbit.event.BusProtoStuffMessageConverter;
import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.junit.Before;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.bus.event.RemoteApplicationEvent;
import org.springframework.cloud.bus.jackson.BusJacksonAutoConfiguration;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.support.MutableMessageHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.converter.AbstractMessageConverter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
/**
* Test the remote entity events.
*/
public abstract class AbstractRemoteEventTest extends AbstractJpaIntegrationTest {
@Autowired
private BusProtoStuffMessageConverter busProtoStuffMessageConverter;
private AbstractMessageConverter jacksonMessageConverter;
@Before
public void setup() throws Exception {
final BusJacksonAutoConfiguration autoConfiguration = new BusJacksonAutoConfiguration();
this.jacksonMessageConverter = autoConfiguration.busJsonConverter();
ReflectionTestUtils.setField(jacksonMessageConverter, "packagesToScan",
new String[] { "org.eclipse.hawkbit.repository.event.remote",
ClassUtils.getPackageName(RemoteApplicationEvent.class) });
((InitializingBean) jacksonMessageConverter).afterPropertiesSet();
}
private Message<?> createProtoStuffMessage(final TenantAwareEvent event) {
final Map<String, Object> headers = Maps.newLinkedHashMap();
headers.put(MessageHeaders.CONTENT_TYPE, BusProtoStuffMessageConverter.APPLICATION_BINARY_PROTOSTUFF);
return busProtoStuffMessageConverter.toMessage(event, new MutableMessageHeaders(headers));
}
private Message<String> createJsonMessage(final Object event) {
final Map<String, MimeType> headers = Maps.newLinkedHashMap();
headers.put(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON);
try {
final String json = new ObjectMapper().writeValueAsString(event);
final Message<String> message = MessageBuilder.withPayload(json).copyHeaders(headers).build();
return message;
} catch (final JsonProcessingException e) {
fail(e.getMessage());
}
return null;
}
protected Message<?> createMessageWithImmutableHeader(final TenantAwareEvent event) {
final Map<String, Object> headers = Maps.newLinkedHashMap();
return busProtoStuffMessageConverter.toMessage(event, new MessageHeaders(headers));
}
protected TenantAwareEvent createJacksonEvent(final TenantAwareEvent event) {
final Message<?> message = createJsonMessage(event);
return (TenantAwareEvent) jacksonMessageConverter.fromMessage(message, event.getClass());
}
protected TenantAwareEvent createProtoStuffEvent(final TenantAwareEvent event) {
final Message<?> message = createProtoStuffMessage(event);
return (TenantAwareEvent) busProtoStuffMessageConverter.fromMessage(message, event.getClass());
}
}

View File

@@ -0,0 +1,82 @@
/**
* 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 static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Entity Id Events")
public class RemoteIdEventTest extends AbstractRemoteEventTest {
private static final long ENTITY_ID = 1L;
@Test
@Description("Verifies that the is ds id correct reloaded")
public void testDistributionSetDeletedEvent() {
assertAndCreateRemoteEvent(DistributionSetDeletedEvent.class);
}
@Test
@Description("Verifies that the ds tag id is correct reloaded")
public void testDistributionSetTagDeletedEvent() {
assertAndCreateRemoteEvent(DistributionSetTagDeletedEvent.class);
}
@Test
@Description("Verifies that the target id is correct reloaded")
public void testTargetDeletedEvent() {
assertAndCreateRemoteEvent(TargetDeletedEvent.class);
}
@Test
@Description("Verifies that the target tag id is correct reloaded")
public void testTargetTagDeletedEvent() {
assertAndCreateRemoteEvent(TargetTagDeletedEvent.class);
}
protected void assertAndCreateRemoteEvent(final Class<? extends RemoteIdEvent> eventType) {
final Constructor<?> constructor = Arrays.stream(eventType.getDeclaredConstructors())
.filter(con -> con.getParameterCount() == 3).findAny()
.orElseThrow(() -> new IllegalArgumentException("Given event is not RemoteIdEvent compatible"));
try {
final RemoteIdEvent event = (RemoteIdEvent) constructor.newInstance("tenant", ENTITY_ID, "Node");
assertEntity(ENTITY_ID, event);
} catch (final ReflectiveOperationException e) {
fail("Exception should not happen " + e.getMessage());
}
}
protected RemoteIdEvent assertEntity(final long id, final RemoteIdEvent event) {
assertThat(event.getEntityId()).isSameAs(id);
RemoteIdEvent underTestCreatedEvent = (RemoteIdEvent) createProtoStuffEvent(event);
assertThat(underTestCreatedEvent.getEntityId()).isEqualTo(id);
underTestCreatedEvent = (RemoteIdEvent) createJacksonEvent(event);
assertThat(underTestCreatedEvent.getEntityId()).isEqualTo(id);
return underTestCreatedEvent;
}
}

View File

@@ -0,0 +1,89 @@
/**
* 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 static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.fail;
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.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Test;
import org.springframework.messaging.converter.MessageConversionException;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Repository")
@Stories("RemoteTenantAwareEvent Tests")
public class RemoteTenantAwareEventTest extends AbstractRemoteEventTest {
@Test
@Description("Verifies that a immutable header is not work")
public void testMessageWithImmutableHeader() {
final DownloadProgressEvent downloadProgressEvent = new DownloadProgressEvent("DEFAULT", 3L, "Node");
try {
createMessageWithImmutableHeader(downloadProgressEvent);
fail("MessageConversionException should happen");
} catch (final MessageConversionException e) {
// ok
}
}
@Test
@Description("Verifies that the download progress reloading by remote events works")
public void reloadDownloadProgessByRemoteEvent() {
final DownloadProgressEvent downloadProgressEvent = new DownloadProgressEvent("DEFAULT", 3L, "Node");
DownloadProgressEvent remoteEvent = (DownloadProgressEvent) createProtoStuffEvent(downloadProgressEvent);
assertThat(downloadProgressEvent).isEqualTo(remoteEvent);
remoteEvent = (DownloadProgressEvent) createJacksonEvent(downloadProgressEvent);
assertThat(downloadProgressEvent).isEqualTo(remoteEvent);
}
@Test
@Description("Verifies that target assignment event works")
public void testTargetAssignDistributionSetEvent() {
final DistributionSet dsA = testdataFactory.createDistributionSet("");
final JpaAction generateAction = (JpaAction) entityFactory.generateAction();
generateAction.setActionType(ActionType.FORCED);
final Target generateTarget = entityFactory.generateTarget("Test");
final Target target = targetManagement.createTarget(generateTarget);
generateAction.setTarget(target);
generateAction.setDistributionSet(dsA);
final Action action = actionRepository.save(generateAction);
final TargetAssignDistributionSetEvent assignmentEvent = new TargetAssignDistributionSetEvent(action,
serviceMatcher.getServiceId());
TargetAssignDistributionSetEvent underTest = (TargetAssignDistributionSetEvent) createProtoStuffEvent(
assignmentEvent);
assertTargetAssignDistributionSetEvent(action, underTest);
underTest = (TargetAssignDistributionSetEvent) createJacksonEvent(assignmentEvent);
assertTargetAssignDistributionSetEvent(action, underTest);
}
private void assertTargetAssignDistributionSetEvent(final Action action,
final TargetAssignDistributionSetEvent underTest) {
assertThat(underTest.getActionId()).isNotNull();
assertThat(underTest.getControllerId()).isNotNull();
assertThat(underTest.getDistributionSetId()).isNotNull();
assertThat(underTest.getActionId()).isEqualTo(action.getId());
assertThat(underTest.getControllerId()).isEqualTo(action.getTarget().getControllerId());
assertThat(underTest.getDistributionSetId()).isEqualTo(action.getDistributionSet().getId());
}
}

View File

@@ -0,0 +1,69 @@
/**
* 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.entity;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.lang.reflect.Constructor;
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEventTest;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Entity Events")
public abstract class AbstractRemoteEntityEventTest<E> extends AbstractRemoteEventTest {
protected RemoteEntityEvent<?> assertAndCreateRemoteEvent(final Class<? extends RemoteEntityEvent<?>> eventType) {
final E baseEntity = createEntity();
final RemoteEntityEvent<?> event = createRemoteEvent(baseEntity, eventType);
assertEntity(baseEntity, event);
return event;
}
protected RemoteEntityEvent<?> createRemoteEvent(final E baseEntity,
final Class<? extends RemoteEntityEvent<?>> eventType) {
Constructor<?> constructor = null;
for (final Constructor<?> constructors : eventType.getDeclaredConstructors()) {
if (constructors.getParameterCount() == 2) {
constructor = constructors;
}
}
if (constructor == null) {
throw new IllegalArgumentException("No suitable constructor foundes");
}
try {
return (RemoteEntityEvent<?>) constructor.newInstance(baseEntity, "Node");
} catch (final ReflectiveOperationException e) {
fail("Exception should not happen " + e.getMessage());
}
return null;
}
protected RemoteEntityEvent<?> assertEntity(final E baseEntity, final RemoteEntityEvent<?> event) {
assertThat(event.getEntity()).isSameAs(baseEntity);
RemoteEntityEvent<?> underTestCreatedEvent = (RemoteEntityEvent<?>) createProtoStuffEvent(event);
assertThat(underTestCreatedEvent.getEntity()).isEqualTo(baseEntity);
underTestCreatedEvent = (RemoteEntityEvent<?>) createJacksonEvent(event);
assertThat(underTestCreatedEvent.getEntity()).isEqualTo(baseEntity);
return underTestCreatedEvent;
}
protected abstract E createEntity();
}

View File

@@ -0,0 +1,53 @@
/**
* 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.entity;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent;
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.Target;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test ActionCreatedEvent and ActionUpdatedEvent")
public class ActionEventTest extends AbstractRemoteEntityEventTest<Action> {
@Test
@Description("Verifies that the action entity reloading by remote created works")
public void testActionCreatedEvent() {
assertAndCreateRemoteEvent(ActionCreatedEvent.class);
}
@Test
@Description("Verifies that the action entity reloading by remote updated works")
public void testActionUpdatedEvent() {
assertAndCreateRemoteEvent(ActionUpdatedEvent.class);
}
@Override
protected Action createEntity() {
final JpaAction generateAction = (JpaAction) entityFactory.generateAction();
generateAction.setActionType(ActionType.FORCED);
final Target generateTarget = entityFactory.generateTarget("Test");
final Target target = targetManagement.createTarget(generateTarget);
generateAction.setTarget(target);
return actionRepository.save(generateAction);
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.entity;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetUpdateEvent;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test DistributionSetCreatedEvent and DistributionSetUpdateEvent")
public class DistributionSetEventTest extends AbstractRemoteEntityEventTest<DistributionSet> {
@Test
@Description("Verifies that the distribution set entity reloading by remote created event works")
public void testDistributionSetCreatedEvent() {
assertAndCreateRemoteEvent(DistributionSetCreatedEvent.class);
}
@Test
@Description("Verifies that the distribution set entity reloading by remote updated event works")
public void testDistributionSetUpdateEvent() {
assertAndCreateRemoteEvent(DistributionSetUpdateEvent.class);
}
@Override
protected DistributionSet createEntity() {
return distributionSetManagement.createDistributionSet(entityFactory.generateDistributionSet("incomplete", "2",
"incomplete", distributionSetManagement.findDistributionSetTypeByKey("os"), null));
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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.entity;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdateEvent;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test DistributionSetTagCreatedEvent and DistributionSetTagUpdateEvent")
public class DistributionSetTagEventTest extends AbstractRemoteEntityEventTest<DistributionSetTag> {
@Test
@Description("Verifies that the distribution set tag entity reloading by remote created event works")
public void testDistributionSetTagCreatedEvent() {
assertAndCreateRemoteEvent(DistributionSetTagCreatedEvent.class);
}
@Test
@Description("Verifies that the distribution set tag entity reloading by remote updated event works")
public void testDistributionSetTagUpdateEvent() {
assertAndCreateRemoteEvent(DistributionSetTagUpdateEvent.class);
}
@Override
protected DistributionSetTag createEntity() {
return tagManagement.createDistributionSetTag(entityFactory.generateDistributionSetTag("tag1"));
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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.entity;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test RolloutUpdatedEvent")
public class RolloutEventTest extends AbstractRemoteEntityEventTest<Rollout> {
@Test
@Description("Verifies that the rollout entity reloading by remote updated event works")
public void testRolloutUpdatedEvent() {
assertAndCreateRemoteEvent(RolloutUpdatedEvent.class);
}
@Override
protected Rollout createEntity() {
targetManagement.createTarget(entityFactory.generateTarget("12345"));
final DistributionSet ds = distributionSetManagement
.createDistributionSet(entityFactory.generateDistributionSet("incomplete", "2", "incomplete",
distributionSetManagement.findDistributionSetTypeByKey("os"), null));
final Rollout rollout = entityFactory.generateRollout();
rollout.setName("exampleRollout");
rollout.setTargetFilterQuery("controllerId==*");
rollout.setDistributionSet(ds);
final JpaRollout entity = (JpaRollout) rolloutManagement.createRollout(rollout, 10,
new RolloutGroupConditionBuilder().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10")
.build());
return entity;
}
}

View File

@@ -0,0 +1,69 @@
/**
* 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.entity;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.UUID;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test RolloutGroupCreatedEvent and RolloutGroupUpdatedEvent")
public class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<RolloutGroup> {
@Test
@Description("Verifies that the rollout group entity reloading by remote created event works")
public void testRolloutGroupCreatedEvent() {
final RolloutGroupCreatedEvent createdEvent = (RolloutGroupCreatedEvent) assertAndCreateRemoteEvent(
RolloutGroupCreatedEvent.class);
assertThat(createdEvent.getRolloutId()).isNotNull();
}
@Test
@Description("Verifies that the rollout group entity reloading by remote updated event works")
public void testRolloutGroupUpdatedEvent() {
assertAndCreateRemoteEvent(RolloutGroupUpdatedEvent.class);
}
@Override
protected RolloutGroup createEntity() {
targetManagement.createTarget(entityFactory.generateTarget(UUID.randomUUID().toString()));
final DistributionSet ds = distributionSetManagement
.createDistributionSet(entityFactory.generateDistributionSet(UUID.randomUUID().toString(), "2",
"incomplete", distributionSetManagement.findDistributionSetTypeByKey("os"), null));
final Rollout rollout = entityFactory.generateRollout();
rollout.setName(UUID.randomUUID().toString());
rollout.setTargetFilterQuery("controllerId==*");
rollout.setDistributionSet(ds);
final JpaRollout entity = (JpaRollout) rolloutManagement.createRollout(rollout, 10,
new RolloutGroupConditionBuilder().successCondition(RolloutGroupSuccessCondition.THRESHOLD, "10")
.build());
return rolloutManagement.findRolloutById(entity.getId()).getRolloutGroups().get(0);
}
}

View File

@@ -0,0 +1,55 @@
/**
* 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.entity;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test TargetCreatedEvent, TargetUpdatedEvent and CancelTargetAssignmentEvent")
public class TargetEventTest extends AbstractRemoteEntityEventTest<Target> {
@Test
@Description("Verifies that the target entity reloading by remote created event works")
public void testTargetCreatedEvent() {
assertAndCreateRemoteEvent(TargetCreatedEvent.class);
}
@Test
@Description("Verifies that the target entity reloading by remote updated event works")
public void testTargetUpdatedEvent() {
assertAndCreateRemoteEvent(TargetUpdatedEvent.class);
}
@Test
@Description("Verifies that cancel target assignment event works")
public void testCancelTargetAssignmentEvent() {
final Target target = createEntity();
final CancelTargetAssignmentEvent assignmentEvent = new CancelTargetAssignmentEvent(target, 1L, "node");
final CancelTargetAssignmentEvent underTest = (CancelTargetAssignmentEvent) assertEntity(target,
assignmentEvent);
assertThat(underTest.getActionId()).isNotNull();
}
@Override
protected Target createEntity() {
return targetManagement.createTarget(entityFactory.generateTarget("12345"));
}
}

View File

@@ -0,0 +1,44 @@
/**
* 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.entity;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdateEvent;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the remote entity events.
*/
@Features("Component Tests - Repository")
@Stories("Test TargetTagCreatedEvent and TargetTagUpdateEvent")
public class TargetTagEventTest extends AbstractRemoteEntityEventTest<TargetTag> {
@Test
@Description("Verifies that the target tag entity reloading by remote created event works")
public void testTargetTagCreatedEvent() {
assertAndCreateRemoteEvent(TargetTagCreatedEvent.class);
}
@Test
@Description("Verifies that the target tag entity reloading by remote updated event works")
public void testTargetTagUpdateEventt() {
assertAndCreateRemoteEvent(TargetTagUpdateEvent.class);
}
@Override
protected TargetTag createEntity() {
return tagManagement.createTargetTag(entityFactory.generateTargetTag("tag1"));
}
}

View File

@@ -22,9 +22,8 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
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.exception.ForceQuitActionNotAllowedException;
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
@@ -41,20 +40,22 @@ 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.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
@@ -69,8 +70,21 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("Deployment Management")
public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
private EventHandlerStub eventHandlerStub;
private CancelEventHandlerStub cancelEventHandlerStub;
@Autowired
private EventBus eventBus;
private ConfigurableApplicationContext applicationContext;
@Before
public void addHandler() {
eventHandlerStub = new EventHandlerStub();
applicationContext.addApplicationListener(eventHandlerStub);
cancelEventHandlerStub = new CancelEventHandlerStub();
applicationContext.addApplicationListener(cancelEventHandlerStub);
}
@Test
@Description("Test verifies that the repistory retrieves the action including all defined (lazy) details.")
@@ -86,6 +100,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(action.getTarget()).as("Target in action").isNotNull();
assertThat(action.getTarget().getAssignedDistributionSet()).as("AssignedDistributionSet of target in action")
.isNotNull();
}
@Test
@@ -377,9 +392,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Simple deployment or distribution set to target assignment test.")
public void assignDistributionSet2Targets() throws InterruptedException {
final EventHandlerMock eventHandlerMock = new EventHandlerMock(20);
eventBus.register(eventHandlerMock);
eventHandlerStub.setExpectedNumberOfEvents(20);
final String myCtrlIDPref = "myCtrlID";
final Iterable<Target> savedNakedTargets = targetManagement
@@ -425,7 +438,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
}
final List<TargetAssignDistributionSetEvent> events = eventHandlerMock.getEvents(10, TimeUnit.SECONDS);
final List<TargetAssignDistributionSetEvent> events = eventHandlerStub.getEvents(10, TimeUnit.SECONDS);
assertTargetAssignDistributionSetEvents(savedDeployedTargets, ds, events);
}
@@ -433,8 +446,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Test that it is not possible to assign a distribution set that is not complete.")
public void failDistributionSetAssigmentThatIsNotComplete() throws InterruptedException {
final EventHandlerMock eventHandlerMock = new EventHandlerMock(0);
eventBus.register(eventHandlerMock);
eventHandlerStub.setExpectedNumberOfEvents(0);
final List<Target> targets = testdataFactory.createTargets(10);
@@ -454,21 +466,20 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
} catch (final IncompleteDistributionSetException ex) {
}
// give some chance to receive events asynchronously
Thread.sleep(1L);
final List<TargetAssignDistributionSetEvent> events = eventHandlerStub.getEvents(5, TimeUnit.SECONDS);
assertThat(events).as("events should be empty").isEmpty();
incomplete.addModule(os);
final DistributionSet nowComplete = distributionSetManagement.updateDistributionSet(incomplete);
// give some chance to receive events asynchronously
Thread.sleep(300);
final List<TargetAssignDistributionSetEvent> events = eventHandlerMock.getEvents(1, TimeUnit.MILLISECONDS);
assertThat(events).as("events should be empty").isEmpty();
final EventHandlerMock eventHandlerMockAfterCompletionOfDs = new EventHandlerMock(10);
eventBus.register(eventHandlerMockAfterCompletionOfDs);
eventHandlerStub.setExpectedNumberOfEvents(10);
assertThat(deploymentManagement.assignDistributionSet(nowComplete, targets).getAssigned())
.as("assign ds doesn't work").isEqualTo(10);
assertTargetAssignDistributionSetEvents(targets, nowComplete,
eventHandlerMockAfterCompletionOfDs.getEvents(10, TimeUnit.SECONDS));
assertTargetAssignDistributionSetEvents(targets, nowComplete, eventHandlerStub.getEvents(15, TimeUnit.SECONDS));
}
@Test
@@ -485,15 +496,12 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
// Each of the four targets get one assignment (4 * 1 = 4)
final int expectedNumberOfEventsForAssignment = 4;
final EventHandlerMock eventHandlerMock = new EventHandlerMock(expectedNumberOfEventsForAssignment);
eventBus.register(eventHandlerMock);
eventHandlerStub.setExpectedNumberOfEvents(expectedNumberOfEventsForAssignment);
// Each of the four targets get two more assignment the which are
// cancelled (4 * 2 = 8)
final int expectedNumberOfEventsForCancel = 8;
final CancelEventHandlerMock cancelEventHandlerMock = new CancelEventHandlerMock(
expectedNumberOfEventsForCancel);
eventBus.register(cancelEventHandlerMock);
cancelEventHandlerStub.setExpectedNumberOfEvents(expectedNumberOfEventsForCancel);
final DeploymentResult deploymentResult = prepareComplexRepo(undeployedTargetPrefix, noOfUndeployedTargets,
deployedTargetPrefix, noOfDeployedTargets, noOfDistributionSets, "myTestDS");
@@ -535,10 +543,10 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
.doesNotContain(Iterables.toArray(deployedTargetsFromDB, JpaTarget.class));
// For each of the 4 targets 1 distribution sets gets assigned
eventHandlerMock.getEvents(10, TimeUnit.SECONDS);
eventHandlerStub.getEvents(10, TimeUnit.SECONDS);
// For each of the 4 targets 2 distribution sets gets cancelled
cancelEventHandlerMock.getEvents(10, TimeUnit.SECONDS);
cancelEventHandlerStub.getEvents(10, TimeUnit.SECONDS);
}
@@ -825,7 +833,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(dsA.getOptLockRevision()).as("lock revision is wrong").isEqualTo(
distributionSetManagement.findDistributionSetByIdWithDetails(dsA.getId()).getOptLockRevision());
final List<Target> targs = new ArrayList<Target>();
final List<Target> targs = new ArrayList<>();
targs.add(targ);
final Iterable<Target> savedTargs = deploymentManagement.assignDistributionSet(dsA, targs).getAssignedEntity();
targ = savedTargs.iterator().next();
@@ -934,17 +942,20 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
private void assertTargetAssignDistributionSetEvents(final List<Target> targets, final DistributionSet ds,
final List<TargetAssignDistributionSetEvent> events) {
assertThat(events).isNotEmpty();
for (final Target myt : targets) {
boolean found = false;
for (final TargetAssignDistributionSetEvent event : events) {
if (event.getTarget().getControllerId().equals(myt.getControllerId())) {
if (event.getControllerId().equals(myt.getControllerId())) {
found = true;
final List<Action> activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(myt);
assertThat(activeActionsByTarget).as("size of active actions for target is wrong").isNotEmpty();
assertThat(event.getActionId()).as("Action id in database and event do not match")
.isEqualTo(activeActionsByTarget.get(0).getId());
assertThat(event.getSoftwareModules()).as("softwaremodule size is not correct")
.containsOnly(ds.getModules().toArray(new SoftwareModule[ds.getModules().size()]));
assertThat(distributionSetManagement.findDistributionSetById(event.getDistributionSetId())
.getModules()).as("softwaremodule size is not correct")
.containsOnly(ds.getModules().toArray(new SoftwareModule[ds.getModules().size()]));
}
}
assertThat(found).as("No event found for controller " + myt.getControllerId()).isTrue();
@@ -952,19 +963,17 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
/**
*
*
*
*/
private class DeploymentResult
private class DeploymentResult {
final List<Long> deployedTargetIDs = new ArrayList<>();
final List<Long> undeployedTargetIDs = new ArrayList<>();
final List<Long> distributionSetIDs = new ArrayList<>();
{
final List<Long> deployedTargetIDs = new ArrayList<Long>();
final List<Long> undeployedTargetIDs = new ArrayList<Long>();
final List<Long> distributionSetIDs = new ArrayList<Long>();
private final List<Target> undeployedTargets = new ArrayList<Target>();
private final List<Target> deployedTargets = new ArrayList<Target>();
private final List<DistributionSet> distributionSets = new ArrayList<DistributionSet>();
private final List<Target> undeployedTargets = new ArrayList<>();
private final List<Target> deployedTargets = new ArrayList<>();
private final List<DistributionSet> distributionSets = new ArrayList<>();
public DeploymentResult(final Iterable<Target> deployedTs, final Iterable<Target> undeployedTs,
final Iterable<DistributionSet> dss, final String deployedTargetPrefix,
@@ -982,101 +991,97 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
}
/**
* @return the distributionSetIDs
*/
public List<Long> getDistributionSetIDs() {
return distributionSetIDs;
}
/**
* @return
*/
public List<Long> getDeployedTargetIDs() {
return deployedTargetIDs;
}
/**
* @return
*/
public List<Target> getUndeployedTargets() {
return undeployedTargets;
}
/**
* @return
*/
public List<DistributionSet> getDistributionSets() {
return distributionSets;
}
/**
* @return
*/
public List<Target> getDeployedTargets() {
return deployedTargets;
}
/**
* @return the undeployedTargetIDs
*/
public List<Long> getUndeployedTargetIDs() {
return undeployedTargetIDs;
}
}
private static class EventHandlerMock {
protected static class EventHandlerStub implements ApplicationListener<TargetAssignDistributionSetEvent> {
private final List<TargetAssignDistributionSetEvent> events = Collections.synchronizedList(new LinkedList<>());
private final CountDownLatch latch;
private final int expectedNumberOfEvents;
private CountDownLatch latch;
private int expectedNumberOfEvents;
private EventHandlerMock(final int expectedNumberOfEvents) {
/**
* @param expectedNumberOfEvents
* the expectedNumberOfEvents to set
*/
public void setExpectedNumberOfEvents(final int expectedNumberOfEvents) {
events.clear();
this.expectedNumberOfEvents = expectedNumberOfEvents;
this.latch = new CountDownLatch(expectedNumberOfEvents);
}
@Subscribe
public void handleEvent(final TargetAssignDistributionSetEvent event) {
events.add(event);
latch.countDown();
}
public List<TargetAssignDistributionSetEvent> getEvents(final long timeout, final TimeUnit unit)
throws InterruptedException {
latch.await(timeout, unit);
final List<TargetAssignDistributionSetEvent> handledEvents = new LinkedList<>(events);
final List<TargetAssignDistributionSetEvent> handledEvents = Collections
.unmodifiableList(new LinkedList<>(events));
assertThat(handledEvents).as("Did not receive the expected amount of events (" + expectedNumberOfEvents
+ ") within timeout. Received events are " + handledEvents).hasSize(expectedNumberOfEvents);
return handledEvents;
}
@Override
public void onApplicationEvent(final TargetAssignDistributionSetEvent event) {
if (latch == null) {
return;
}
events.add(event);
latch.countDown();
}
}
private static class CancelEventHandlerMock {
private static class CancelEventHandlerStub implements ApplicationListener<CancelTargetAssignmentEvent> {
private final List<CancelTargetAssignmentEvent> events = Collections.synchronizedList(new LinkedList<>());
private final CountDownLatch latch;
private final int expectedNumberOfEvents;
private CountDownLatch latch;
private int expectedNumberOfEvents;
private CancelEventHandlerMock(final int expectedNumberOfEvents) {
public void setExpectedNumberOfEvents(final int expectedNumberOfEvents) {
events.clear();
this.expectedNumberOfEvents = expectedNumberOfEvents;
this.latch = new CountDownLatch(expectedNumberOfEvents);
}
@Subscribe
public void handleEvent(final CancelTargetAssignmentEvent event) {
events.add(event);
latch.countDown();
}
public List<CancelTargetAssignmentEvent> getEvents(final long timeout, final TimeUnit unit)
throws InterruptedException {
latch.await(timeout, unit);
final List<CancelTargetAssignmentEvent> handledEvents = new LinkedList<CancelTargetAssignmentEvent>(events);
final List<CancelTargetAssignmentEvent> handledEvents = new LinkedList<>(events);
assertThat(handledEvents).as("Did not receive the expected amount of events (" + expectedNumberOfEvents
+ ") within timeout. Received events are " + handledEvents).hasSize(expectedNumberOfEvents);
return handledEvents;
}
@Override
public void onApplicationEvent(final CancelTargetAssignmentEvent event) {
if (latch == null) {
return;
}
events.add(event);
latch.countDown();
}
}
}

View File

@@ -16,7 +16,6 @@ import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
@@ -35,6 +34,7 @@ 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.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;

View File

@@ -20,7 +20,6 @@ import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.ReportManagement;
import org.eclipse.hawkbit.repository.ReportManagement.DateTypes;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
@@ -30,6 +29,7 @@ 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.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;

View File

@@ -269,7 +269,7 @@ public class TagManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Ensures that a deleted tag is removed from the repository as defined.")
public void deleteTargetTas() {
public void deleteTargetTags() {
// create test data
final Iterable<JpaTargetTag> tags = createTargetsWithTags();

View File

@@ -29,7 +29,6 @@ import javax.persistence.Query;
import javax.validation.ConstraintViolationException;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
@@ -39,6 +38,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
import org.eclipse.hawkbit.repository.model.Tag;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetIdName;

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.repository.jpa;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import java.io.Serializable;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
@@ -222,7 +223,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes
public void requestConfigValueWithWrongType() {
try {
tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL,
Object.class);
Serializable.class);
Assert.fail("");
} catch (final TenantConfigurationValidatorException e) {

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.repository.jpa.cache;
import static org.fest.assertions.api.Assertions.assertThat;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Repository")
@Stories("CacheKeys")
public class CacheKeysTest {
@Test
public void entitySpecificCacheKeyPattern() {
final String knownEntityId = "123";
final String knownCacheKey = "someField";
final String entitySpecificCacheKey = CacheKeys.entitySpecificCacheKey(knownEntityId, knownCacheKey);
assertThat(entitySpecificCacheKey).isEqualTo(knownEntityId + "." + knownCacheKey);
}
}

View File

@@ -1,73 +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.repository.jpa.cache;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.eclipse.hawkbit.repository.eventbus.event.DownloadProgressEvent;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.tenancy.TenantAware;
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.cache.Cache;
import org.springframework.cache.CacheManager;
import com.google.common.eventbus.EventBus;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Repository")
@Stories("CacheWriteNotify")
@RunWith(MockitoJUnitRunner.class)
public class CacheWriteNotifyTest {
@Mock
private EventBus eventBusMock;
@Mock
private CacheManager cacheManagerMock;
@Mock
private Cache cacheMock;
@Mock
private TenantAware tenantAwareMock;
private CacheWriteNotify underTest;
@Before
public void before() {
underTest = new CacheWriteNotify();
underTest.setEventBus(eventBusMock);
underTest.setCacheManager(cacheManagerMock);
underTest.setTenantAware(tenantAwareMock);
}
@Test
public void downloadgProgressIsCachedAndEventSent() {
final long knownStatusId = 1;
when(cacheManagerMock.getCache(ActionStatus.class.getName())).thenReturn(cacheMock);
when(tenantAwareMock.getCurrentTenant()).thenReturn("default");
underTest.downloadProgress(knownStatusId, 500L, 100L, 100L);
verify(cacheManagerMock).getCache(eq(ActionStatus.class.getName()));
verify(cacheMock).put(knownStatusId + "." + CacheKeys.DOWNLOAD_PROGRESS_PERCENT, 20);
verify(eventBusMock).post(any(DownloadProgressEvent.class));
}
}

View File

@@ -6,33 +6,31 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.eventbus;
package org.eclipse.hawkbit.repository.jpa.event;
import static org.fest.assertions.Assertions.assertThat;
import java.net.URI;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.hawkbit.eventbus.event.Event;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.event.TenantAwareEvent;
import org.eclipse.hawkbit.repository.event.remote.DistributionSetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.event.RepositoryEntityEventTest.RepositoryTestConfiguration;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.fest.assertions.api.Assertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
@@ -40,17 +38,15 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Repository")
@Stories("Entity Events")
@SpringApplicationConfiguration(classes = RepositoryTestConfiguration.class)
public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
@Autowired
private EventBus eventBus;
private final MyEventListener eventListener = new MyEventListener();
private MyEventListener eventListener;
@Before
public void beforeTest() {
eventListener.queue.clear();
eventBus.register(eventListener);
}
@Test
@@ -77,19 +73,6 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
assertThat(targetUpdatedEvent.getEntity().getId()).isEqualTo(createdTarget.getId());
}
@Test
@Description("Verifies that the target info update event is published when a target info has been updated")
public void targetInfoUpdateEventIsPublished() throws InterruptedException {
final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345"));
controllerManagament.updateTargetStatus(createdTarget.getTargetInfo(), TargetUpdateStatus.PENDING,
System.currentTimeMillis(), URI.create("http://127.0.0.1"));
final TargetInfoUpdateEvent targetInfoUpdatedEvent = eventListener.waitForEvent(TargetInfoUpdateEvent.class, 1,
TimeUnit.SECONDS);
assertThat(targetInfoUpdatedEvent).isNotNull();
assertThat(targetInfoUpdatedEvent.getEntity().getTarget().getId()).isEqualTo(createdTarget.getId());
}
@Test
@Description("Verifies that the target deleted event is published when a target has been deleted")
public void targetDeletedEventIsPublished() throws InterruptedException {
@@ -100,7 +83,7 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
final TargetDeletedEvent targetDeletedEvent = eventListener.waitForEvent(TargetDeletedEvent.class, 1,
TimeUnit.SECONDS);
assertThat(targetDeletedEvent).isNotNull();
assertThat(targetDeletedEvent.getTargetId()).isEqualTo(createdTarget.getId());
assertThat(targetDeletedEvent.getEntityId()).isEqualTo(createdTarget.getId());
}
@Test
@@ -112,8 +95,8 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
final DistributionSet createDistributionSet = distributionSetManagement
.createDistributionSet(generateDistributionSet);
final DistributionCreatedEvent dsCreatedEvent = eventListener.waitForEvent(DistributionCreatedEvent.class, 1,
TimeUnit.SECONDS);
final DistributionSetCreatedEvent dsCreatedEvent = eventListener.waitForEvent(DistributionSetCreatedEvent.class,
1, TimeUnit.SECONDS);
assertThat(dsCreatedEvent).isNotNull();
assertThat(dsCreatedEvent.getEntity().getId()).isEqualTo(createDistributionSet.getId());
}
@@ -130,24 +113,33 @@ public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest {
distributionSetManagement.deleteDistributionSet(createDistributionSet);
final DistributionDeletedEvent dsDeletedEvent = eventListener.waitForEvent(DistributionDeletedEvent.class, 1,
TimeUnit.SECONDS);
final DistributionSetDeletedEvent dsDeletedEvent = eventListener.waitForEvent(DistributionSetDeletedEvent.class,
1, TimeUnit.SECONDS);
assertThat(dsDeletedEvent).isNotNull();
assertThat(dsDeletedEvent.getDistributionSetId()).isEqualTo(createDistributionSet.getId());
assertThat(dsDeletedEvent.getEntityId()).isEqualTo(createDistributionSet.getId());
}
private class MyEventListener {
public static class RepositoryTestConfiguration {
private final BlockingQueue<Event> queue = new LinkedBlockingQueue<>();
@Bean
public MyEventListener myEventListenerBean() {
return new MyEventListener();
}
@Subscribe
public void onEvent(final Event event) {
}
private static class MyEventListener {
private final BlockingQueue<TenantAwareEvent> queue = new LinkedBlockingQueue<>();
@EventListener(classes = TenantAwareEvent.class)
public void onEvent(final TenantAwareEvent event) {
queue.offer(event);
}
public <T> T waitForEvent(final Class<T> eventType, final long timeout, final TimeUnit timeUnit)
throws InterruptedException {
Event event = null;
TenantAwareEvent event = null;
while ((event = queue.poll(timeout, timeUnit)) != null) {
if (event.getClass().isAssignableFrom(eventType)) {
return (T) event;

View File

@@ -1,129 +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.repository.jpa.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.verify;
import static org.mockito.Mockito.when;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.jpa.model.CacheFieldEntityListener;
import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder;
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.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.hateoas.Identifiable;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Repository")
@Stories("EventBus")
@RunWith(MockitoJUnitRunner.class)
public class CacheFieldEntityListenerTest {
private static final String TEST_CACHE_FIELD = "testCacheField";
@Mock
private CacheManager cacheManagerMock;
@Mock
private Cache cacheMock;
private CacheFieldEntityListener underTest;
@Before
public void before() {
// mock
when(cacheManagerMock.getCache(anyString())).thenReturn(cacheMock);
underTest = new CacheFieldEntityListener();
CacheManagerHolder.getInstance().setCacheManager(cacheManagerMock);
}
@Test
public void postLoadSetsCacheFields() {
final String entityId = "123";
final String normalFieldValue = "bumlux";
final TestEntity testObject = new TestEntity(entityId, normalFieldValue);
final int expectedTestValue = -1;
when(cacheMock.get(CacheKeys.entitySpecificCacheKey(entityId, TEST_CACHE_FIELD)))
.thenReturn(new SimpleValueWrapper(expectedTestValue));
// pre verify everything is ok
assertThat(testObject.getCacheField()).isNotEqualTo(expectedTestValue);
assertThat(testObject.getNormalField()).isEqualTo(normalFieldValue);
// test
underTest.postLoad(testObject);
assertThat(testObject.getNormalField()).isEqualTo(normalFieldValue);
// now cache value should be like the value in the mock of the cache
assertThat(testObject.getCacheField()).isEqualTo(expectedTestValue);
}
@Test
public void postRemoveEvictsCacheField() {
final String entityId = "123";
final String normalFieldValue = "bumlux";
final TestEntity testObject = new TestEntity(entityId, normalFieldValue);
// test
underTest.postDelete(testObject);
verify(cacheMock).evict(eq(CacheKeys.entitySpecificCacheKey(entityId, TEST_CACHE_FIELD)));
}
private final class TestEntity implements Identifiable<String> {
private final String id;
private final String normalField;
@CacheField(key = TEST_CACHE_FIELD)
private int cacheField;
private TestEntity(final String id, final String normalFieldValue) {
this.id = id;
this.normalField = normalFieldValue;
}
/*
* (non-Javadoc)
*
* @see org.springframework.hateoas.Identifiable#getId()
*/
@Override
public String getId() {
return id;
}
/**
* @return the normalField
*/
String getNormalField() {
return normalField;
}
/**
* @return the cacheField
*/
int getCacheField() {
return cacheField;
}
}
}

View File

@@ -26,12 +26,13 @@ import org.eclipse.hawkbit.repository.FieldNameProvider;
import org.eclipse.hawkbit.repository.SoftwareModuleFields;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.TimestampCalculator;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.TimestampCalculator;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@@ -18,8 +18,9 @@ import java.time.Instant;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
import org.eclipse.hawkbit.repository.jpa.TimestampCalculator;
import org.eclipse.hawkbit.repository.TimestampCalculator;
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.junit.Before;

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.persistence" level="DEBUG" /> -->
<Root level="INFO">
<appender-ref ref="CONSOLE" />
</Root>
</configuration>