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;