Merge branch 'master' into feature_enable_push_in_deployment_view

Conflicts:
	hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java
This commit is contained in:
gah6kor
2016-07-19 16:09:47 +02:00
90 changed files with 1677 additions and 1538 deletions

View File

@@ -54,6 +54,7 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManage
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.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
@@ -71,6 +72,8 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import com.google.common.eventbus.EventBus;
/**
* General configuration for hawkBit's Repository.
*
@@ -85,6 +88,9 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
@EnableConfigurationProperties(RepositoryProperties.class)
@EnableScheduling
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Autowired
private EventBus eventBus;
/**
* @return the {@link SystemSecurityContext} singleton bean which make it
* accessible in beans which cannot access the service directly,
@@ -249,7 +255,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Bean
@ConditionalOnMissingBean
public TenantStatsManagement tenantStatsManagement() {
return new JpaTenantStatsManagement();
final TenantStatsManagement mgmt = new JpaTenantStatsManagement();
eventBus.register(mgmt);
return mgmt;
}
/**

View File

@@ -451,8 +451,8 @@ public class JpaControllerManagement implements ControllerManagement {
@Override
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void addInformationalActionStatus(final ActionStatus statusMessage) {
actionStatusRepository.save((JpaActionStatus) statusMessage);
public ActionStatus addInformationalActionStatus(final ActionStatus statusMessage) {
return actionStatusRepository.save((JpaActionStatus) statusMessage);
}
@Override
@@ -469,8 +469,9 @@ public class JpaControllerManagement implements ControllerManagement {
}
@Override
public void downloadProgressPercent(final long statusId, final int progressPercent) {
cacheWriteNotify.downloadProgressPercent(statusId, progressPercent);
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
final Long shippedBytesOverall) {
cacheWriteNotify.downloadProgress(statusId, requestedBytes, shippedBytesSinceLast, shippedBytesOverall);
}
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa;
import java.util.Collection;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
@@ -87,6 +88,14 @@ public class JpaEntityFactory implements EntityFactory {
return new JpaTarget(controllerId);
}
@Override
public Target generateTarget(final String controllerId, final String securityToken) {
if (StringUtils.isEmpty(securityToken)) {
return new JpaTarget(controllerId);
}
return new JpaTarget(controllerId, securityToken);
}
@Override
public TargetTag generateTargetTag() {
return new JpaTargetTag();

View File

@@ -132,7 +132,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId());
boolean updated = false;
if (sm.getDescription() != null && !sm.getDescription().equals(type.getDescription())) {
if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) {
type.setDescription(sm.getDescription());
updated = true;
}

View File

@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.repository.Constants;
import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.TenantStatsManagement;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
@@ -26,6 +27,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.TenantMetaData;
import org.eclipse.hawkbit.repository.report.model.SystemUsageReport;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,11 +35,14 @@ import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.validation.annotation.Validated;
/**
@@ -108,7 +113,10 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
private SystemManagementCacheKeyGenerator currentTenantCacheKeyGenerator;
@Autowired
private ApplicationContext applicationContext;
private SystemSecurityContext systemSecurityContext;
@Autowired
private PlatformTransactionManager txManager;
@Override
public SystemUsageReport getSystemUsageStatistics() {
@@ -147,7 +155,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
final List<String> tenants = findTenants();
tenants.forEach(tenant -> tenantAware.runAsTenant(tenant, () -> {
report.addTenantData(systemStatsManagement.getStatsOfTenant(tenant));
report.addTenantData(systemStatsManagement.getStatsOfTenant());
return null;
}));
}
@@ -159,27 +167,48 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
@Override
@Cacheable(value = "tenantMetadata", key = "#tenant.toUpperCase()")
@Cacheable(value = "tenantMetadata", key = "#tenant.toUpperCase()", cacheManager = "directCacheManager")
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Modifying
public TenantMetaData getTenantMetadata(final String tenant) {
final TenantMetaData result = tenantMetaDataRepository.findByTenantIgnoreCase(tenant);
// Create if it does not exist
if (result == null) {
try {
currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant);
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
applicationContext.getBean("currentTenantKeyGenerator");
return tenantMetaDataRepository.save(new JpaTenantMetaData(createStandardSoftwareDataSetup(), tenant));
return createInitialTenantMetaData(tenant);
} finally {
currentTenantCacheKeyGenerator.getCreateInitialTenant().remove();
}
}
return result;
}
/**
* Creating the initial tenant meta-data in a new transaction. Due the
* {@link MultiTenantJpaTransactionManager} is using the current tenant to
* set the necessary tenant discriminator to the query. This is not working
* if we don't have a current tenant set. Due the
* {@link #getTenantMetadata(String)} is maybe called without having a
* current tenant we need to re-open a new transaction so the
* {@link MultiTenantJpaTransactionManager} is called again and set the
* tenant for this transaction.
*
* @param tenant
* the tenant to be created
* @return the initial created {@link TenantMetaData}
*/
private TenantMetaData createInitialTenantMetaData(final String tenant) {
final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("initial-tenant-creation");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
return systemSecurityContext.runAsSystemAsTenant(
() -> new TransactionTemplate(txManager, def).execute(status -> tenantMetaDataRepository
.save(new JpaTenantMetaData(createStandardSoftwareDataSetup(), tenant))),
tenant);
}
@Override
public List<String> findTenants() {
return tenantMetaDataRepository.findAll().stream().map(md -> md.getTenant()).collect(Collectors.toList());
@@ -191,7 +220,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
@Modifying
public void deleteTenant(final String tenant) {
cacheManager.evictCaches(tenant);
cacheManager.getCache("currentTenant").evict(currentTenantKeyGenerator().generate(null, null));
tenantAware.runAsTenant(tenant, () -> {
entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, tenant.toUpperCase());
tenantMetaDataRepository.deleteByTenantIgnoreCase(tenant);
@@ -226,7 +254,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
@Override
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator")
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager")
// set transaction to not supported, due we call this in
// BaseEntity#prePersist methods
// and it seems that JPA committing the transaction when executing this

View File

@@ -12,8 +12,8 @@ import java.util.Optional;
import org.eclipse.hawkbit.repository.TenantStatsManagement;
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -35,9 +35,14 @@ public class JpaTenantStatsManagement implements TenantStatsManagement {
@Autowired
private ActionRepository actionRepository;
@Autowired
private TenantAware tenantAware;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_UNCOMMITTED)
public TenantUsage getStatsOfTenant(final String tenant) {
public TenantUsage getStatsOfTenant() {
final String tenant = tenantAware.getCurrentTenant();
final TenantUsage result = new TenantUsage(tenant);
result.setTargets(targetRepository.count());

View File

@@ -8,9 +8,10 @@
*/
package org.eclipse.hawkbit.repository.jpa.cache;
import org.eclipse.hawkbit.eventbus.event.DownloadProgressEvent;
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.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -20,6 +21,7 @@ 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
@@ -30,10 +32,6 @@ import com.google.common.eventbus.EventBus;
*/
@Service
public class CacheWriteNotify {
/**
*
*/
private static final int DOWNLOAD_PROGRESS_MAX = 100;
@Autowired
@@ -46,20 +44,29 @@ public class CacheWriteNotify {
private TenantAware tenantAware;
/**
* writes the download progress in percentage into the cache
* 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 progressPercent
* the progress in percentage which must be between 0-100
* @param requestedBytes
* requested bytes of the request
* @param shippedBytesSinceLast
* since last event
* @param shippedBytesOverall
* for the download request
*/
public void downloadProgressPercent(final long statusId, final int progressPercent) {
public void downloadProgress(final Long statusId, final Long requestedBytes, final Long shippedBytesSinceLast,
final Long shippedBytesOverall) {
final Cache cache = cacheManager.getCache(Action.class.getName());
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 {
@@ -69,7 +76,8 @@ public class CacheWriteNotify {
cache.evict(cacheKey);
}
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, progressPercent));
eventBus.post(new DownloadProgressEvent(tenantAware.getCurrentTenant(), statusId, requestedBytes,
shippedBytesSinceLast, shippedBytesOverall));
}
/**

View File

@@ -27,10 +27,7 @@ import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
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.ActionStatus;
import org.eclipse.hawkbit.repository.model.DistributionSet;
@@ -89,13 +86,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
private JpaRollout rollout;
/**
* Note: filled only in {@link Status#DOWNLOAD}.
*/
@Transient
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
private int downloadProgressPercent;
@Override
public DistributionSet getDistributionSet() {
return distributionSet;
@@ -120,15 +110,6 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
this.status = status;
}
@Override
public int getDownloadProgressPercent() {
return downloadProgressPercent;
}
public void setDownloadProgressPercent(final int downloadProgressPercent) {
this.downloadProgressPercent = downloadProgressPercent;
}
@Override
public boolean isActive() {
return active;

View File

@@ -24,7 +24,10 @@ import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.Table;
import javax.persistence.Transient;
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;
@@ -63,6 +66,13 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
@Column(name = "detail_message", length = 512)
private final List<String> messages = new ArrayList<>();
/**
* Note: filled only in {@link Status#DOWNLOAD}.
*/
@Transient
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
private int downloadProgressPercent;
/**
* Creates a new {@link ActionStatus} object.
*
@@ -105,6 +115,11 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
// JPA default constructor.
}
@Override
public int getDownloadProgressPercent() {
return downloadProgressPercent;
}
@Override
public Long getOccurredAt() {
return occurredAt;

View File

@@ -115,9 +115,21 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
* controller ID of the {@link Target}
*/
public JpaTarget(final String controllerId) {
this(controllerId, SecurityTokenGeneratorHolder.getInstance().generateToken());
}
/**
* Constructor.
*
* @param controllerId
* controller ID of the {@link Target}
* @param securityToken
* for target authentication if enabled
*/
public JpaTarget(final String controllerId, final String securityToken) {
this.controllerId = controllerId;
setName(controllerId);
securityToken = SecurityTokenGeneratorHolder.getInstance().generateToken();
this.securityToken = securityToken;
targetInfo = new JpaTargetInfo(this);
}