From 4f7bb98587972182977d81b894e80aa76edcb9b5 Mon Sep 17 00:00:00 2001 From: Asharani Date: Tue, 28 Jun 2016 12:07:26 +0530 Subject: [PATCH 01/28] Enable push for update target, create/update/delete ds Renamed constant MAX_TARGET_TABLE_ENTRIES Signed-off-by: Asharani --- .../eventbus/event/TargetDeletedEvent.java | 39 ---- .../event/DistributionCreatedEvent.java | 28 +++ .../event/DistributionDeletedEvent.java | 37 ++++ .../event/DistributionSetUpdateEvent.java | 30 +++ .../eventbus/event/TargetDeletedEvent.java | 41 ++++ .../eventbus/event/TargetUpdatedEvent.java | 25 +++ .../jpa/JpaDistributionSetManagement.java | 56 ++++-- .../repository/jpa/JpaTargetManagement.java | 22 +- .../eventbus/EntityChangeEventListener.java | 154 -------------- .../model/AbstractDescriptorEventVisitor.java | 19 ++ .../AbstractDescriptorEventVisitorImpl.java | 189 ++++++++++++++++++ .../jpa/model/AbstractJpaBaseEntity.java | 7 +- .../repository/jpa/model/AcceptVisitor.java | 18 ++ .../jpa/model/DescriptorEventDetails.java | 42 ++++ .../model/EntityPropertyChangeListener.java | 78 ++------ .../hawkbit/ui/HawkbitEventProvider.java | 14 +- .../dstable/DistributionSetTable.java | 108 +++++++++- .../dstable/ManageDistBeanQuery.java | 2 +- .../CustomTargetBeanQuery.java | 6 +- .../footer/TargetFilterCountMessageLabel.java | 6 +- .../DistributionAddUpdateWindowLayout.java | 17 +- .../dstable/DistributionBeanQuery.java | 2 +- .../management/dstable/DistributionTable.java | 97 +++++++++ .../management/footer/CountMessageLabel.java | 6 +- .../ManangementConfirmationWindowLayout.java | 1 - .../targettable/TargetBeanQuery.java | 6 +- .../management/targettable/TargetTable.java | 48 ++++- .../RolloutGroupTargetsBeanQuery.java | 6 +- .../RolloutGroupTargetsCountLabelMessage.java | 6 +- .../hawkbit/ui/utils/SPUIDefinitions.java | 15 +- 30 files changed, 788 insertions(+), 337 deletions(-) delete mode 100644 hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetDeletedEvent.java create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java delete mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetDeletedEvent.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetDeletedEvent.java deleted file mode 100644 index e6fcac135..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/eventbus/event/TargetDeletedEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.eventbus.event; - -/** - * - * - * - */ -public class TargetDeletedEvent extends AbstractDistributedEvent { - - private static final long serialVersionUID = 1L; - private final long targetId; - - /** - * @param tenant - * the tenant for this event - * @param targetId - * the ID of the target which has been deleted - */ - public TargetDeletedEvent(final String tenant, final long targetId) { - super(-1, tenant); - this.targetId = targetId; - } - - /** - * @return the targetId - */ - public long getTargetId() { - return targetId; - } - -} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java new file mode 100644 index 000000000..20515521d --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionCreatedEvent.java @@ -0,0 +1,28 @@ +/** + * 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.eventbus.event; + +import org.eclipse.hawkbit.repository.model.DistributionSet; + +/** + * Defines the {@link AbstractBaseEntityEvent} of creating a new {@link DistributionSet}. + * + */ +public class DistributionCreatedEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 1L; + + /** + * @param distributionSet + * the distributionSet which has been created + */ + public DistributionCreatedEvent(final DistributionSet distributionSet) { + super(distributionSet); + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java new file mode 100644 index 000000000..1edfb47ac --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java @@ -0,0 +1,37 @@ +/** + * 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.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; +import org.eclipse.hawkbit.repository.model.DistributionSet; + + +/** + * * Defines the {@link AbstractDistributedEvent} for deletion of {@link DistributionSet}. + + * + */ +public class DistributionDeletedEvent extends AbstractDistributedEvent{ + private static final long serialVersionUID = -3308850381757843098L; + final Long[] distributionSetIDs; + /** + * @param tenant + * the tenant for this event + * @param distributionSetId + * the ID of the target which has been deleted + */ + public DistributionDeletedEvent(final String tenant, final Long...distributionIds) { + super(-1, tenant); + this.distributionSetIDs = distributionIds; + } + + public Long[] getDistributionSetIDs() { + return distributionSetIDs; + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java new file mode 100644 index 000000000..8d91d27f7 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionSetUpdateEvent.java @@ -0,0 +1,30 @@ +/** + * 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.eventbus.event; + +import org.eclipse.hawkbit.repository.model.DistributionSet; + +/** + * Defines the {@link AbstractBaseEntityEvent} for update a {@link DistributionSet}. + * + */ +public class DistributionSetUpdateEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 1L; + + /** + * Constructor. + * + * @param tag + * the tag which is updated + */ + public DistributionSetUpdateEvent(final DistributionSet ds) { + super(ds); + } +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java new file mode 100644 index 000000000..637a0dcc5 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetDeletedEvent.java @@ -0,0 +1,41 @@ +/** + * 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.eventbus.event; + +import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; +import org.eclipse.hawkbit.repository.model.Target; + +/** + * + * Defines the {@link AbstractBaseEntityEvent} of deleting a {@link Target}. + */ +public class TargetDeletedEvent extends AbstractDistributedEvent { + + private static final long serialVersionUID = 1L; + private final long targetId; + + /** + * @param tenant + * the tenant for this event + * @param targetId + * the ID of the target which has been deleted + */ + public TargetDeletedEvent(final String tenant, final long targetId) { + super(-1, tenant); + this.targetId = targetId; + } + + /** + * @return the targetId + */ + public long getTargetId() { + return targetId; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java new file mode 100644 index 000000000..a30d96c69 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java @@ -0,0 +1,25 @@ +/** + * 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.eventbus.event; + +import org.eclipse.hawkbit.repository.model.Target; + +/** + * Defines the {@link AbstractBaseEntityEvent} of updating a {@link Target}. + * + */ +public class TargetUpdatedEvent extends AbstractBaseEntityEvent { + + private static final long serialVersionUID = 5665118668865832477L; + + public TargetUpdatedEvent(Target baseEntity) { + super(baseEntity); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 0e97d6ff5..b94677fb9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -28,6 +28,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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityLockedException; @@ -54,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; 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.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -102,6 +104,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private TenantAware tenantAware; + @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); @@ -168,32 +173,39 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteDistributionSet(final Long... distributionSetIDs) { - final List toHardDelete = new ArrayList<>(); + public void deleteDistributionSet(final Long... distributionSetIDs) { + final List toHardDelete = new ArrayList<>(); - final List assigned = distributionSetRepository - .findAssignedToTargetDistributionSetsById(distributionSetIDs); - assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs)); + final List assigned = distributionSetRepository + .findAssignedToTargetDistributionSetsById(distributionSetIDs); + assigned.addAll(distributionSetRepository + .findAssignedToRolloutDistributionSetsById(distributionSetIDs)); - // soft delete assigned - if (!assigned.isEmpty()) { - distributionSetRepository.deleteDistributionSet(assigned.toArray(new Long[assigned.size()])); - } + // soft delete assigned + if (!assigned.isEmpty()) { + distributionSetRepository.deleteDistributionSet(assigned + .toArray(new Long[assigned.size()])); + } - // mark the rest as hard delete - for (final Long setId : distributionSetIDs) { - if (!assigned.contains(setId)) { - toHardDelete.add(setId); - } - } + // mark the rest as hard delete + for (final Long setId : distributionSetIDs) { + if (!assigned.contains(setId)) { + toHardDelete.add(setId); + } + } - // hard delete the rest if exixts - if (!toHardDelete.isEmpty()) { - // don't give the delete statement an empty list, JPA/Oracle cannot - // handle the empty list - distributionSetRepository.deleteByIdIn(toHardDelete); - } - } + // hard delete the rest if exixts + if (!toHardDelete.isEmpty()) { + // don't give the delete statement an empty list, JPA/Oracle cannot + // handle the empty list + distributionSetRepository.deleteByIdIn(toHardDelete); + } + + afterCommit.afterCommit(() -> eventBus + .post(new DistributionDeletedEvent(tenantAware + .getCurrentTenant(), distributionSetIDs))); + + } @Override @Modifying diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 1cd2ffc3c..30a5dd5d9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -29,6 +29,7 @@ import javax.persistence.criteria.Root; 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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -48,6 +49,7 @@ import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; 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.data.domain.Page; @@ -96,6 +98,10 @@ public class JpaTargetManagement implements TargetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + + + @Autowired + private TenantAware tenantAware; @Override public Target findTargetByControllerID(final String controllerId) { @@ -202,12 +208,14 @@ public class JpaTargetManagement implements TargetManagement { // hibernate session. final List targetsForCurrentTenant = targetRepository.findAll(Lists.newArrayList(targetIDs)).stream() .map(Target::getId).collect(Collectors.toList()); - if (!targetsForCurrentTenant.isEmpty()) { - targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); - targetRepository.deleteByIdIn(targetsForCurrentTenant); - } + if (!targetsForCurrentTenant.isEmpty()) { + targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); + targetRepository.deleteByIdIn(targetsForCurrentTenant); + targetsForCurrentTenant.forEach(targetId -> notifyTargetDeleted( + tenantAware.getCurrentTenant(), targetId)); + } } - + @Override public Page findTargetByAssignedDistributionSet(final Long distributionSetID, final Pageable pageReq) { return targetRepository.findByAssignedDistributionSetId(pageReq, distributionSetID); @@ -651,5 +659,9 @@ public class JpaTargetManagement implements TargetManagement { } return resultList; } + + private void notifyTargetDeleted(final String tenant, final Long targetId) { + afterCommit.afterCommit(() -> eventBus.post(new TargetDeletedEvent(tenant, targetId))); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java deleted file mode 100644 index 5f41063d2..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/eventbus/EntityChangeEventListener.java +++ /dev/null @@ -1,154 +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.Collection; - -import javax.persistence.EntityManager; - -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; -import org.eclipse.hawkbit.repository.jpa.TargetRepository; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -import org.eclipse.hawkbit.tenancy.TenantAware; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.google.common.eventbus.EventBus; - -/** - * An aspect implementation which wraps the necessary repository services for - * saving {@link TenantAwareBaseEntity}s to publish create or update events. - * - * - * - * - */ -@Service -@Aspect -public class EntityChangeEventListener { - - @Autowired - private EventBus eventBus; - - @Autowired - private TenantAware tenantAware; - - @Autowired - private EntityManager entityManager; - - @Autowired - private AfterTransactionCommitExecutor afterCommit; - - /** - * In case the a {@link Target} is created a corresponding - * {@link TargetInfo} is created as well. We need the {@link TargetInfo} - * information in the target created event. So we are listening to the - * {@link TargetInfo} creation to indicate if an Target has been created. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetInfoRepository.save(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112" }) - public Object targetCreated(final ProceedingJoinPoint joinpoint) throws Throwable { - final boolean isNew = isTargetInfoNew(joinpoint.getArgs()[0]); - final Object result = joinpoint.proceed(); - if (result instanceof TargetInfo) { - if (isNew) { - notifyTargetCreated(entityManager.merge(entityManager.merge(((TargetInfo) result).getTarget()))); - } else { - notifyTargetInfoChanged((TargetInfo) result); - } - } - return result; - } - - /** - * Proxy method around the delete method of the {@link TargetRepository} to - * notify the {@link TargetDeletedEvent} in case targets has been deleted. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.deleteByIdIn(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112" }) - public Object targetDeletedById(final ProceedingJoinPoint joinpoint) throws Throwable { - final String currentTenant = tenantAware.getCurrentTenant(); - final Object result = joinpoint.proceed(); - final Collection targetIds = (Collection) joinpoint.getArgs()[0]; - targetIds.forEach(targetId -> notifyTargetDeleted(currentTenant, targetId)); - return result; - } - - /** - * Proxy method around the delete method of the {@link TargetRepository} to - * notify the {@link TargetDeletedEvent} in case targets has been deleted. - * - * @param joinpoint - * the aspect join point - * @return the object of the {@link ProceedingJoinPoint#proceed()} - * @throws Throwable - * in case exception happens in the - * {@link ProceedingJoinPoint#proceed()} - */ - @Around("execution(* org.eclipse.hawkbit.repository.jpa.TargetRepository.delete(..))") - // Exception squid:S00112 - Is aspectJ proxy - @SuppressWarnings({ "squid:S00112", "unchecked" }) - public Object targetDeleted(final ProceedingJoinPoint joinpoint) throws Throwable { - final String currentTenant = tenantAware.getCurrentTenant(); - final Object result = joinpoint.proceed(); - final Object param = joinpoint.getArgs()[0]; - // delete by id - if (param instanceof Long) { - notifyTargetDeleted(currentTenant, (Long) param); - } else if (param instanceof Target) { - notifyTargetDeleted(currentTenant, ((Target) param).getId()); - } else if (param instanceof Iterable) { - ((Iterable) param).forEach(target -> notifyTargetDeleted(currentTenant, target.getId())); - } - return result; - } - - private void notifyTargetCreated(final Target t) { - afterCommit.afterCommit(() -> eventBus.post(new TargetCreatedEvent(t))); - - } - - private void notifyTargetInfoChanged(final TargetInfo targetInfo) { - afterCommit.afterCommit(() -> eventBus.post(new TargetInfoUpdateEvent(targetInfo))); - } - - private void notifyTargetDeleted(final String tenant, final Long targetId) { - afterCommit.afterCommit(() -> eventBus.post(new TargetDeletedEvent(tenant, targetId))); - } - - private static boolean isTargetInfoNew(final Object targetInfo) { - return ((JpaTargetInfo) targetInfo).isNew(); - } - -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java new file mode 100644 index 000000000..ce32b025f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java @@ -0,0 +1,19 @@ +/** + * 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; + +/** + * + * Interface defining the action to be performed after entity is + * created/updated. + * + */ +public interface AbstractDescriptorEventVisitor { + void publishEventPostAction(DescriptorEventDetails eventDetails); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java new file mode 100644 index 000000000..8755f8051 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java @@ -0,0 +1,189 @@ +/** + * 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; +import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.EventBus; + +/** + * Implementation of @link{AbstractDescriptorEventVisitor} .Publishes the + * appropriate event after any action on entity like create/update. + * + */ +public class AbstractDescriptorEventVisitorImpl implements + AbstractDescriptorEventVisitor { + + private static final String COMPLETE = "complete"; + private static final Logger LOG = LoggerFactory + .getLogger(AbstractDescriptorEventVisitorImpl.class); + + @Override + public void publishEventPostAction(final DescriptorEventDetails event) { + Method method = null; + DescriptorEvent descriptorEvent = event.getDescriptorEvent(); + ActionType actiontype = event.getActiontype(); + try { + method = getMethod(descriptorEvent, actiontype); + if (method != null) { + method.invoke(this, descriptorEvent.getObject(), + descriptorEvent); + } + } catch (NoSuchMethodException | SecurityException + | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) { + LOG.info( + "Exception when invoking approriate method to publis event {}", + e); + } + } + + private Method getMethod(DescriptorEvent descriptorEvent, + ActionType actiontype) throws NoSuchMethodException { + if (actiontype == ActionType.UPDATE) { + return this.getClass().getMethod("publishEventAfterUpdate", + descriptorEvent.getObject().getClass(), + DescriptorEvent.class); + } else if (actiontype == ActionType.CREATE) { + return this.getClass().getMethod("publishEventAfterCreate", + descriptorEvent.getObject().getClass(), + DescriptorEvent.class); + } + return null; + } + + public void publishEventAfterCreate(JpaAction action, DescriptorEvent event) { + if (action.getRollout() != null) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post(new ActionCreatedEvent(action))); + } + } + + public void publishEventAfterCreate(JpaTarget target, DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post(new TargetCreatedEvent(target))); + } + + public void publishEventAfterCreate(JpaDistributionSet ds, + DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post(new DistributionCreatedEvent(ds))); + + } + + public void publishEventAfterUpdate(JpaAction action, DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post( + new ActionPropertyChangeEvent(action, getChangeSet( + Action.class, event)))); + } + + public void publishEventAfterUpdate(JpaTarget target, DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post(new TargetUpdatedEvent(target))); + } + + public void publishEventAfterUpdate(JpaTargetInfo targetInfo, + DescriptorEvent event) { + getAfterTransactionCommmitExecutor() + .afterCommit( + () -> getEventBus().post( + new TargetInfoUpdateEvent(targetInfo))); + } + + public void publishEventAfterUpdate(JpaRollout entity, DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post( + new RolloutPropertyChangeEvent(entity, getChangeSet( + Rollout.class, event)))); + } + + public void publishEventAfterUpdate(JpaRolloutGroup entity, + DescriptorEvent event) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post( + new RolloutGroupPropertyChangeEvent(entity, + getChangeSet(RolloutGroup.class, event)))); + + } + + public void publishEventAfterUpdate(JpaDistributionSet entity, + DescriptorEvent event) { + Map.Values> changeSet = getChangeSet( + JpaDistributionSet.class, event); + if (changeSet.containsKey(COMPLETE) + && changeSet.get(COMPLETE).getOldValue().equals(false) + && changeSet.get(COMPLETE).getNewValue().equals(true)) { + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus().post( + new DistributionCreatedEvent(entity))); + } + + getAfterTransactionCommmitExecutor().afterCommit( + () -> getEventBus() + .post(new DistributionSetUpdateEvent(entity))); + + } + + private Map.Values> getChangeSet( + final Class clazz, final DescriptorEvent event) { + final T rolloutGroup = clazz.cast(event.getObject()); + 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 AbstractPropertyChangeEvent( + rolloutGroup, null).new Values(record + .getOldValue(), record.getNewValue()))); + } + + private AfterTransactionCommitExecutor getAfterTransactionCommmitExecutor() { + return AfterTransactionCommitExecutorHolder.getInstance() + .getAfterCommit(); + } + + private EventBus getEventBus() { + return EventBusHolder.getInstance().getEventBus(); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java index 257828c6f..2785676fb 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java @@ -32,7 +32,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @MappedSuperclass @Access(AccessType.FIELD) @EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class }) -public abstract class AbstractJpaBaseEntity implements BaseEntity { +public abstract class AbstractJpaBaseEntity implements BaseEntity,AcceptVisitor { private static final long serialVersionUID = 1L; @Id @@ -178,4 +178,9 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity { return true; } + + @Override + public void postActionOnEntity(AbstractDescriptorEventVisitor visitor, DescriptorEventDetails eventDetails){ + visitor.publishEventPostAction(eventDetails); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java new file mode 100644 index 000000000..78d89219b --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java @@ -0,0 +1,18 @@ +/** + * 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; + +/** + * Interface to accept visitor @link{AbstractDescriptorEventVisitor}. + * + */ +public interface AcceptVisitor { + public void postActionOnEntity(AbstractDescriptorEventVisitor visitor, + DescriptorEventDetails eventDetails); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java new file mode 100644 index 000000000..a13d0700c --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model; + +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * + * Holds details of action(Create/Update) and @link{DescriptorEvent}. + * + */ +public class DescriptorEventDetails { + + enum ActionType { + CREATE, UPDATE; + } + + private DescriptorEvent descriptorEvent; + + private ActionType actiontype; + + public DescriptorEventDetails(ActionType actionType, + DescriptorEvent descriptorEvent) { + this.descriptorEvent = descriptorEvent; + this.actiontype = actionType; + } + + public DescriptorEvent getDescriptorEvent() { + return descriptorEvent; + } + + public ActionType getActiontype() { + return actiontype; + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index 2dd0fdb40..bdb366edb 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -8,28 +8,9 @@ */ package org.eclipse.hawkbit.repository.jpa.model; -import java.util.Map; -import java.util.stream.Collectors; - -import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; +import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; -import org.eclipse.persistence.internal.sessions.ObjectChangeSet; -import org.eclipse.persistence.queries.UpdateObjectQuery; -import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord; - -import com.google.common.eventbus.EventBus; /** * Listens to change in property values of an entity. @@ -37,50 +18,19 @@ import com.google.common.eventbus.EventBus; */ public class EntityPropertyChangeListener extends DescriptorEventAdapter { - @Override - public void postInsert(final DescriptorEvent event) { - if (event.getObject().getClass().equals(Action.class)) { - final Action action = (Action) event.getObject(); - if (action.getRollout() != null) { - final EventBus eventBus = getEventBus(); - final AfterTransactionCommitExecutor afterCommit = getAfterTransactionCommmitExecutor(); - afterCommit.afterCommit(() -> eventBus.post(new ActionCreatedEvent(action))); - } - } + @Override + public void postInsert(final DescriptorEvent event) { + AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl(); + ((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor, + new DescriptorEventDetails(ActionType.CREATE, event)); - } + } - @Override - public void postUpdate(final DescriptorEvent event) { - if (event.getObject().getClass().equals(JpaAction.class)) { - getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( - new ActionPropertyChangeEvent((Action) event.getObject(), getChangeSet(Action.class, event)))); - } else if (event.getObject().getClass().equals(JpaRollout.class)) { - getAfterTransactionCommmitExecutor().afterCommit(() -> getEventBus().post( - new RolloutPropertyChangeEvent((Rollout) event.getObject(), getChangeSet(Rollout.class, event)))); - } else if (event.getObject().getClass().equals(JpaRolloutGroup.class)) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new RolloutGroupPropertyChangeEvent((RolloutGroup) event.getObject(), - getChangeSet(RolloutGroup.class, event)))); - } - } - - private Map.Values> getChangeSet( - final Class clazz, final DescriptorEvent event) { - final T rolloutGroup = clazz.cast(event.getObject()); - 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 AbstractPropertyChangeEvent(rolloutGroup, null).new Values( - record.getOldValue(), record.getNewValue()))); - } - - private AfterTransactionCommitExecutor getAfterTransactionCommmitExecutor() { - return AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit(); - } - - private EventBus getEventBus() { - return EventBusHolder.getInstance().getEventBus(); - } + @Override + public void postUpdate(final DescriptorEvent event) { + AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl(); + ((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor, + new DescriptorEventDetails(ActionType.UPDATE, event)); + } + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java index cca4bdd4c..f064a76a1 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEventProvider.java @@ -12,25 +12,29 @@ import java.util.HashSet; import java.util.Set; import org.eclipse.hawkbit.eventbus.event.Event; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagCreatedBulkEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.eventbus.event.RolloutChangeEvent; import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupChangeEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagCreatedBulkEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetTagUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; /** * The default hawkbit event provider. */ public class HawkbitEventProvider implements UIEventProvider { - private static final Set> SINGLE_EVENTS = new HashSet<>(6); - private static final Set> BULK_EVENTS = new HashSet<>(3); + private static final Set> SINGLE_EVENTS = new HashSet<>(9); + private static final Set> BULK_EVENTS = new HashSet<>(5); static { SINGLE_EVENTS.add(TargetTagCreatedBulkEvent.class); @@ -41,10 +45,14 @@ public class HawkbitEventProvider implements UIEventProvider { SINGLE_EVENTS.add(RolloutGroupChangeEvent.class); SINGLE_EVENTS.add(RolloutChangeEvent.class); SINGLE_EVENTS.add(TargetTagUpdateEvent.class); + SINGLE_EVENTS.add(DistributionSetUpdateEvent.class); BULK_EVENTS.add(TargetCreatedEvent.class); BULK_EVENTS.add(TargetInfoUpdateEvent.class); BULK_EVENTS.add(TargetDeletedEvent.class); + BULK_EVENTS.add(DistributionDeletedEvent.class); + BULK_EVENTS.add(DistributionCreatedEvent.class); + BULK_EVENTS.add(TargetUpdatedEvent.class); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index a52c0b683..9430dc135 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -21,6 +21,9 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; +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.model.DistributionSet; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleIdName; @@ -116,6 +119,33 @@ public class DistributionSetTable extends AbstractNamedVersionTable visibleItemIds = (List) getVisibleItemIds(); + + // refresh the details tabs only if selected ds is updated + if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { + // update table row+details layout + eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, ds)); + } else if (visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent()) { + // update the name/version details visible in table + UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); + } + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvents(final List events) { + final Object firstEvent = events.get(0); + if (DistributionCreatedEvent.class.isInstance(firstEvent)) { + refreshDistributions(); + } else if (DistributionDeletedEvent.class.isInstance(firstEvent)) { + onDistributionDeleteEvent((List) events); + } + } + @Override protected String getTableId() { return SPUIComponentIdProvider.DIST_TABLE_ID; @@ -422,11 +452,15 @@ public class DistributionSetTable extends AbstractNamedVersionTable updateDistributionInTable(event.getEntity())); } @EventBusListenerMethod(scope = EventScope.SESSION) void onEvent(final SaveActionWindowEvent event) { - if (event == SaveActionWindowEvent.DELETED_DISTRIBUTIONS || event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) { + if (event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) { UI.getCurrent().access(() -> refreshFilter()); } } @@ -467,6 +501,78 @@ public class DistributionSetTable extends AbstractNamedVersionTable events) { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shouldRefreshDs = false; + for (final DistributionDeletedEvent deletedEvent : events) { + Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); + for (Long dsId : distributionSetIDs) { + final DistributionSetIdName targetIdName = new DistributionSetIdName(dsId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; + } + } + } + + if (shouldRefreshDs) { + refreshOnDelete(); + } else { + dsContainer.commit(); + } + reSelectItemsAfterDeletionEvent(); + } + + private void refreshOnDelete() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + refreshTablecontainer(); + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void reSelectItemsAfterDeletionEvent() { + Set values = new HashSet<>(); + if (isMultiSelect()) { + values = new HashSet<>((Set) getValue()); + } else { + values.add(getValue()); + } + setValue(null); + + for (final Object value : values) { + if (getVisibleItemIds().contains(value)) { + select(value); + } + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java index a262f0d20..efe28beb5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java @@ -42,7 +42,7 @@ import com.google.common.base.Strings; public class ManageDistBeanQuery extends AbstractBeanQuery { private static final long serialVersionUID = 5176481314404662215L; - private Sort sort = new Sort(Direction.ASC, "name", "version"); + private Sort sort = new Sort(Direction.ASC, "createdAt"); private String searchText = null; private transient DistributionSetManagement distributionSetManagement; private transient Page firstPageDistributionSets = null; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java index 35f88f5a1..80c9b0497 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java @@ -155,9 +155,9 @@ public class CustomTargetBeanQuery extends AbstractBeanQuery { size = getTargetManagement().countTargetByTargetFilterQuery(filterQuery); } getFilterManagementUIState().setTargetsCountAll(size); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - getFilterManagementUIState().setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - size = SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + getFilterManagementUIState().setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + size = SPUIDefinitions.MAX_TABLE_ENTRIES; } else { getFilterManagementUIState().setTargetsTruncated(null); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java index 4700b48eb..c82467425 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java @@ -93,7 +93,7 @@ public class TargetFilterCountMessageLabel extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("label.target.filter.truncated", filterManagementUIState.getTargetsTruncated(), - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + SPUIDefinitions.MAX_TABLE_ENTRIES)); } else { setIcon(null); @@ -102,8 +102,8 @@ public class TargetFilterCountMessageLabel extends Label { targetMessage.append(totalTargets); targetMessage.append(HawkbitCommonUtil.SP_STRING_SPACE); targetMessage.append(i18n.get("label.filter.shown")); - if (totalTargets > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - targetMessage.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + if (totalTargets > SPUIDefinitions.MAX_TABLE_ENTRIES) { + targetMessage.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { targetMessage.append(HawkbitCommonUtil.SP_STRING_SPACE); targetMessage.append(totalTargets); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java index 5b5d53524..6c79f3b3d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java @@ -10,8 +10,10 @@ package org.eclipse.hawkbit.ui.management.dstable; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.PostConstruct; @@ -23,10 +25,10 @@ import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetType; import org.eclipse.hawkbit.repository.model.TenantMetaData; import org.eclipse.hawkbit.ui.common.CommonDialogWindow; +import org.eclipse.hawkbit.ui.common.DistributionSetIdName; import org.eclipse.hawkbit.ui.common.DistributionSetTypeBeanQuery; -import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; -import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; +import org.eclipse.hawkbit.ui.distributions.dstable.DistributionSetTable; import org.eclipse.hawkbit.ui.management.event.DragEvent; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.I18N; @@ -89,6 +91,9 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { @Autowired private transient EntityFactory entityFactory; + + @Autowired + private transient DistributionSetTable distributionSetTable; private TextField distNameTextField; private TextField distVersionTextField; @@ -243,8 +248,6 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { distributionSetManagement.updateDistributionSet(currentDS); notificationMessage.displaySuccess(i18n.get("message.new.dist.save.success", new Object[] { currentDS.getName(), currentDS.getVersion() })); - // update table row+details layout - eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, currentDS)); } catch (final EntityAlreadyExistsException entityAlreadyExistsException) { LOG.error("Update distribution failed {}", entityAlreadyExistsException); notificationMessage.displayValidationError( @@ -289,8 +292,10 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { new Object[] { newDist.getName(), newDist.getVersion() })); /* close the window */ closeThisWindow(); - - eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.NEW_ENTITY, newDist)); + + final Set s = new HashSet<>(); + s.add(new DistributionSetIdName(newDist.getId(),newDist.getName(),newDist.getVersion())); + distributionSetTable.setValue(s); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java index 63ed91250..672cc0a1c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java @@ -41,7 +41,7 @@ import com.google.common.base.Strings; public class DistributionBeanQuery extends AbstractBeanQuery { private static final long serialVersionUID = 5862679853949173536L; - private Sort sort = new Sort(Direction.ASC, "name", "version"); + private Sort sort = new Sort(Direction.ASC, "createdAt"); private Collection distributionTags; private String searchText; private String pinnedControllerId; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index 5b265fc14..056abf12e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -20,6 +20,9 @@ import org.apache.commons.lang3.StringUtils; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; +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.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; import org.eclipse.hawkbit.repository.model.Target; @@ -105,6 +108,35 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + final Object firstEvent = events.get(0); + if (DistributionDeletedEvent.class.isInstance(firstEvent)) { + onDistributionDeleteEvent((List) events); + } else if (DistributionCreatedEvent.class.isInstance(firstEvent) + && ((DistributionCreatedEvent) firstEvent).getEntity().isComplete()) { + refreshDistributions(); + } + + } + + @EventBusListenerMethod(scope = EventScope.SESSION) + void onEvents(final DistributionSetUpdateEvent event) { + final DistributionSet ds = event.getEntity(); + final DistributionSetIdName lastSelectedDsIdName = managementUIState.getLastSelectedDsIdName(); + final List visibleItemIds = (List) getVisibleItemIds(); + + // refresh the details tabs only if selected ds is updated + // refresh the details tabs only if selected ds is updated + if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { + // update table row+details layout + eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, ds)); + } else if (visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent()) { + //update the name/version details visible in table + UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); + } + } + /** * DistributionTableFilterEvent. * @@ -658,4 +690,69 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shouldRefreshDs = false; + for (final DistributionDeletedEvent deletedEvent : events) { + Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); + for (Long dsId : distributionSetIDs) { + final DistributionSetIdName targetIdName = new DistributionSetIdName(dsId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; + } + } + } + + if (shouldRefreshDs) { + refreshOnDelete(); + } else { + dsContainer.commit(); + } + reSelectItemsAfterDeletionEvent(); + } + + private void reSelectItemsAfterDeletionEvent() { + Set values = new HashSet<>(); + if (isMultiSelect()) { + values = new HashSet<>((Set) getValue()); + } else { + values.add(getValue()); + } + setValue(null); + + for (final Object value : values) { + if (getVisibleItemIds().contains(value)) { + select(value); + } + } + } + + private void refreshDistributions() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + if (size < SPUIDefinitions.MAX_TABLE_ENTRIES) { + refreshTablecontainer(); + } + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void refreshOnDelete() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + final int size = dsContainer.size(); + refreshTablecontainer(); + if (size != 0) { + setData(SPUIDefinitions.DATA_AVAILABLE); + } + } + + private void refreshTablecontainer() { + final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); + dsContainer.refresh(); + selectRow(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java index fccee7cb5..6cf01410d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/CountMessageLabel.java @@ -174,7 +174,7 @@ public class CountMessageLabel extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("label.target.filter.truncated", managementUIState.getTargetsTruncated(), - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + SPUIDefinitions.MAX_TABLE_ENTRIES)); totalTargetTableEnteries += managementUIState.getTargetsTruncated(); } else { setIcon(null); @@ -184,9 +184,9 @@ public class CountMessageLabel extends Label { final StringBuilder message = new StringBuilder(i18n.get("label.target.filter.count")); message.append(managementUIState.getTargetsCountAll()); message.append(HawkbitCommonUtil.SP_STRING_SPACE); - if (totalTargetTableEnteries > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (totalTargetTableEnteries > SPUIDefinitions.MAX_TABLE_ENTRIES) { message.append(i18n.get("label.filter.shown")); - message.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + message.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { if (!targFilParams.hasFilter()) { message.append(i18n.get("label.filter.shown")); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java index 1a9d3572f..e4c56b165 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/footer/ManangementConfirmationWindowLayout.java @@ -387,7 +387,6 @@ public class ManangementConfirmationWindowLayout extends AbstractConfirmationWin managementUIState.getTargetTableFilters().getPinnedDistId() .ifPresent(distId -> unPinDeletedDS(deletedIds, distId)); - eventBus.publish(this, SaveActionWindowEvent.DELETED_DISTRIBUTIONS); managementUIState.getDeletedDistributionList().clear(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java index e96a9af8e..6ce3c5cb6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java @@ -190,9 +190,9 @@ public class TargetBeanQuery extends AbstractBeanQuery { final ManagementUIState tmpManagementUIState = getManagementUIState(); tmpManagementUIState.setTargetsCountAll(totSize); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - tmpManagementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - size = SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + tmpManagementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + size = SPUIDefinitions.MAX_TABLE_ENTRIES; } else { tmpManagementUIState.setTargetsTruncated(null); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 0a70f60d5..0a0eaaa7e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -17,11 +17,12 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.eclipse.hawkbit.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetInfo; @@ -142,6 +143,8 @@ public class TargetTable extends AbstractTable { onTargetInfoUpdateEvents((List) events); } else if (TargetDeletedEvent.class.isInstance(firstEvent)) { onTargetDeletedEvent((List) events); + } else if(TargetUpdatedEvent.class.isInstance(firstEvent)){ + onTargetUpdateEvents((List) events); } } @@ -809,7 +812,7 @@ public class TargetTable extends AbstractTable { private void refreshTargets() { final LazyQueryContainer targetContainer = (LazyQueryContainer) getContainerDataSource(); final int size = targetContainer.size(); - if (size < SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (size < SPUIDefinitions.MAX_TABLE_ENTRIES) { refreshTablecontainer(); } else { // If table is not refreshed , explicitly target total count and @@ -829,10 +832,12 @@ public class TargetTable extends AbstractTable { final TargetIdName targetIdName) { final LazyQueryContainer targetContainer = (LazyQueryContainer) getContainerDataSource(); final Item item = targetContainer.getItem(targetIdName); - item.getItemProperty(SPUILabelDefinitions.VAR_TARGET_STATUS).setValue(targetInfo.getUpdateStatus()); item.getItemProperty(SPUILabelDefinitions.VAR_NAME).setValue(target.getName()); - item.getItemProperty(SPUILabelDefinitions.VAR_POLL_STATUS_TOOL_TIP) - .setValue(HawkbitCommonUtil.getPollStatusToolTip(targetInfo.getPollStatus(), i18n)); + if (targetInfo != null) { + item.getItemProperty(SPUILabelDefinitions.VAR_POLL_STATUS_TOOL_TIP).setValue( + HawkbitCommonUtil.getPollStatusToolTip(targetInfo.getPollStatus(), i18n)); + item.getItemProperty(SPUILabelDefinitions.VAR_TARGET_STATUS).setValue(targetInfo.getUpdateStatus()); + } } private boolean isLastSelectedTarget(final TargetIdName targetIdName) { @@ -879,6 +884,35 @@ public class TargetTable extends AbstractTable { } } + + private void onTargetUpdateEvents(List events) { + final List visibleItemIds = (List) getVisibleItemIds(); + boolean shoulTargetsUpdated = false; + Target lastSelectedTarget = null; + for (final TargetUpdatedEvent targetUpdatedEvent : events) { + Target target = targetUpdatedEvent.getEntity(); + final TargetIdName targetIdName = target.getTargetIdName(); + if (Filters.or(getTargetTableFilters(target)).doFilter()) { + shoulTargetsUpdated = true; + } else { + if (visibleItemIds.contains(targetIdName)) { + updateVisibleItemOnEvent(null, target, targetIdName); + } + } + if (isLastSelectedTarget(targetIdName)) { + lastSelectedTarget = target; + } + } + if (shoulTargetsUpdated) { + refreshTargets(); + } + if (lastSelectedTarget != null) { + eventBus.publish(this, new TargetTableEvent(BaseEntityEventType.SELECTED_ENTITY, lastSelectedTarget)); + } + } + + + private void onTargetCreatedEvents() { refreshTargets(); } @@ -953,8 +987,8 @@ public class TargetTable extends AbstractTable { size = getTargetsCountWithFilter(totalTargetsCount, status, targetTags, distributionId, searchText, noTagClicked, pinnedDistId); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + managementUIState.setTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java index 685be685e..487f05ae5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java @@ -140,9 +140,9 @@ public class RolloutGroupTargetsBeanQuery extends AbstractBeanQuery size = firstPageTargetSets.getTotalElements(); } getRolloutUIState().setRolloutGroupTargetsTotalCount(size); - if (size > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { - getRolloutUIState().setRolloutGroupTargetsTruncated(size - SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); - return SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES; + if (size > SPUIDefinitions.MAX_TABLE_ENTRIES) { + getRolloutUIState().setRolloutGroupTargetsTruncated(size - SPUIDefinitions.MAX_TABLE_ENTRIES); + return SPUIDefinitions.MAX_TABLE_ENTRIES; } return (int) size; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java index c791a0eb2..e5c716e83 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java @@ -94,7 +94,7 @@ public class RolloutGroupTargetsCountLabelMessage extends Label { // set the icon setIcon(FontAwesome.INFO_CIRCLE); setDescription(i18n.get("rollout.group.label.target.truncated", - rolloutUIState.getRolloutGroupTargetsTruncated(), SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES)); + rolloutUIState.getRolloutGroupTargetsTruncated(), SPUIDefinitions.MAX_TABLE_ENTRIES)); totalTargetTableEnteries += rolloutUIState.getRolloutGroupTargetsTruncated(); } else { setIcon(null); @@ -104,9 +104,9 @@ public class RolloutGroupTargetsCountLabelMessage extends Label { final StringBuilder message = new StringBuilder(i18n.get("label.target.filter.count")); message.append(rolloutUIState.getRolloutGroupTargetsTotalCount()); message.append(HawkbitCommonUtil.SP_STRING_SPACE); - if (totalTargetTableEnteries > SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES) { + if (totalTargetTableEnteries > SPUIDefinitions.MAX_TABLE_ENTRIES) { message.append(i18n.get("label.filter.shown")); - message.append(SPUIDefinitions.MAX_TARGET_TABLE_ENTRIES); + message.append(SPUIDefinitions.MAX_TABLE_ENTRIES); } else { message.append(i18n.get("label.filter.shown")); message.append(rolloutGroupTargetsListGrid.getContainerDataSource().size()); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java index 1a6e8c163..1766485f6 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIDefinitions.java @@ -268,10 +268,6 @@ public final class SPUIDefinitions { * New Target save icon id. */ public static final String NEW_TARGET_SAVE = "target.add.save"; - /** - * New Target discard icon id. - */ - // public static final String NEW_TARGET_DISCARD = "target.add.discard"; /** * New Target add icon id. */ @@ -344,15 +340,6 @@ public final class SPUIDefinitions { * New Target tag color lable id. */ public static final String NEW_TARGET_TAG_COLOR = "target.tag.add.color"; - /** - * New Target tag save icon id. - */ - // public static final String NEW_TARGET_TAG_SAVE = "target.tag.add.save"; - /** - * New Target tag discard icon id. - */ - // public static final String NEW_TARGET_TAG_DISRACD = - // "target.tag.add.discard"; /** * New Target tag add icon id. */ @@ -860,7 +847,7 @@ public final class SPUIDefinitions { * truncates it. This protects to endless scroll to very high page numbers * which is very in performant. */ - public static final int MAX_TARGET_TABLE_ENTRIES = 5000; + public static final int MAX_TABLE_ENTRIES = 5000; /** * New software module set type add icon id. From 5f1db53defb244763315731257b1a9d85cfec6c1 Mon Sep 17 00:00:00 2001 From: GAH6KOR Date: Thu, 21 Jul 2016 12:39:54 +0200 Subject: [PATCH 02/28] Removed the extra level of abstraction and modified the code accordingly. --- .../AbstractDescriptorEventVisitorImpl.java | 189 ----- .../jpa/model/AbstractJpaBaseEntity.java | 6 +- .../repository/jpa/model/AcceptVisitor.java | 18 - .../model/EntityPropertyChangeListener.java | 31 +- ...ventVisitor.java => EventAwareEntity.java} | 17 +- .../repository/jpa/model/JpaAction.java | 373 +++++----- .../jpa/model/JpaDistributionSet.java | 602 ++++++++-------- .../repository/jpa/model/JpaRollout.java | 423 +++++------ .../repository/jpa/model/JpaRolloutGroup.java | 500 ++++++------- .../repository/jpa/model/JpaTarget.java | 491 +++++++------ .../repository/jpa/model/JpaTargetInfo.java | 668 +++++++++--------- .../helper/EntityPropertyChangeHelper.java | 42 ++ 12 files changed, 1673 insertions(+), 1687 deletions(-) delete mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java delete mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java rename hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/{AbstractDescriptorEventVisitor.java => EventAwareEntity.java} (53%) create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java deleted file mode 100644 index 8755f8051..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitorImpl.java +++ /dev/null @@ -1,189 +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.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.stream.Collectors; - -import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; -import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; -import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor; -import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; -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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.eventbus.EventBus; - -/** - * Implementation of @link{AbstractDescriptorEventVisitor} .Publishes the - * appropriate event after any action on entity like create/update. - * - */ -public class AbstractDescriptorEventVisitorImpl implements - AbstractDescriptorEventVisitor { - - private static final String COMPLETE = "complete"; - private static final Logger LOG = LoggerFactory - .getLogger(AbstractDescriptorEventVisitorImpl.class); - - @Override - public void publishEventPostAction(final DescriptorEventDetails event) { - Method method = null; - DescriptorEvent descriptorEvent = event.getDescriptorEvent(); - ActionType actiontype = event.getActiontype(); - try { - method = getMethod(descriptorEvent, actiontype); - if (method != null) { - method.invoke(this, descriptorEvent.getObject(), - descriptorEvent); - } - } catch (NoSuchMethodException | SecurityException - | IllegalAccessException | IllegalArgumentException - | InvocationTargetException e) { - LOG.info( - "Exception when invoking approriate method to publis event {}", - e); - } - } - - private Method getMethod(DescriptorEvent descriptorEvent, - ActionType actiontype) throws NoSuchMethodException { - if (actiontype == ActionType.UPDATE) { - return this.getClass().getMethod("publishEventAfterUpdate", - descriptorEvent.getObject().getClass(), - DescriptorEvent.class); - } else if (actiontype == ActionType.CREATE) { - return this.getClass().getMethod("publishEventAfterCreate", - descriptorEvent.getObject().getClass(), - DescriptorEvent.class); - } - return null; - } - - public void publishEventAfterCreate(JpaAction action, DescriptorEvent event) { - if (action.getRollout() != null) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new ActionCreatedEvent(action))); - } - } - - public void publishEventAfterCreate(JpaTarget target, DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new TargetCreatedEvent(target))); - } - - public void publishEventAfterCreate(JpaDistributionSet ds, - DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new DistributionCreatedEvent(ds))); - - } - - public void publishEventAfterUpdate(JpaAction action, DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post( - new ActionPropertyChangeEvent(action, getChangeSet( - Action.class, event)))); - } - - public void publishEventAfterUpdate(JpaTarget target, DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post(new TargetUpdatedEvent(target))); - } - - public void publishEventAfterUpdate(JpaTargetInfo targetInfo, - DescriptorEvent event) { - getAfterTransactionCommmitExecutor() - .afterCommit( - () -> getEventBus().post( - new TargetInfoUpdateEvent(targetInfo))); - } - - public void publishEventAfterUpdate(JpaRollout entity, DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post( - new RolloutPropertyChangeEvent(entity, getChangeSet( - Rollout.class, event)))); - } - - public void publishEventAfterUpdate(JpaRolloutGroup entity, - DescriptorEvent event) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post( - new RolloutGroupPropertyChangeEvent(entity, - getChangeSet(RolloutGroup.class, event)))); - - } - - public void publishEventAfterUpdate(JpaDistributionSet entity, - DescriptorEvent event) { - Map.Values> changeSet = getChangeSet( - JpaDistributionSet.class, event); - if (changeSet.containsKey(COMPLETE) - && changeSet.get(COMPLETE).getOldValue().equals(false) - && changeSet.get(COMPLETE).getNewValue().equals(true)) { - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus().post( - new DistributionCreatedEvent(entity))); - } - - getAfterTransactionCommmitExecutor().afterCommit( - () -> getEventBus() - .post(new DistributionSetUpdateEvent(entity))); - - } - - private Map.Values> getChangeSet( - final Class clazz, final DescriptorEvent event) { - final T rolloutGroup = clazz.cast(event.getObject()); - 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 AbstractPropertyChangeEvent( - rolloutGroup, null).new Values(record - .getOldValue(), record.getNewValue()))); - } - - private AfterTransactionCommitExecutor getAfterTransactionCommmitExecutor() { - return AfterTransactionCommitExecutorHolder.getInstance() - .getAfterCommit(); - } - - private EventBus getEventBus() { - return EventBusHolder.getInstance().getEventBus(); - } - -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java index 2785676fb..c2e91afea 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractJpaBaseEntity.java @@ -32,7 +32,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @MappedSuperclass @Access(AccessType.FIELD) @EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class }) -public abstract class AbstractJpaBaseEntity implements BaseEntity,AcceptVisitor { +public abstract class AbstractJpaBaseEntity implements BaseEntity { private static final long serialVersionUID = 1L; @Id @@ -179,8 +179,4 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity,AcceptVisitor } - @Override - public void postActionOnEntity(AbstractDescriptorEventVisitor visitor, DescriptorEventDetails eventDetails){ - visitor.publishEventPostAction(eventDetails); - } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java deleted file mode 100644 index 78d89219b..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AcceptVisitor.java +++ /dev/null @@ -1,18 +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; - -/** - * Interface to accept visitor @link{AbstractDescriptorEventVisitor}. - * - */ -public interface AcceptVisitor { - public void postActionOnEntity(AbstractDescriptorEventVisitor visitor, - DescriptorEventDetails eventDetails); -} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index bdb366edb..df36309df 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -8,7 +8,6 @@ */ package org.eclipse.hawkbit.repository.jpa.model; -import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; @@ -18,19 +17,23 @@ import org.eclipse.persistence.descriptors.DescriptorEventAdapter; */ public class EntityPropertyChangeListener extends DescriptorEventAdapter { - @Override - public void postInsert(final DescriptorEvent event) { - AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl(); - ((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor, - new DescriptorEventDetails(ActionType.CREATE, event)); + @Override + public void postInsert(final DescriptorEvent event) { + + final Object object = event.getObject(); + if (object instanceof EventAwareEntity) { + ((EventAwareEntity) object).fireCreateEvent(object,event); + } + } + + @Override + public void postUpdate(final DescriptorEvent event) { + + final Object object = event.getObject(); + if (object instanceof EventAwareEntity) { + ((EventAwareEntity) object).fireUpdateEvent(object,event); + } + } - } - @Override - public void postUpdate(final DescriptorEvent event) { - AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl(); - ((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor, - new DescriptorEventDetails(ActionType.UPDATE, event)); - } - } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java similarity index 53% rename from hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java rename to hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java index ce32b025f..2c1fe51d2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/AbstractDescriptorEventVisitor.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java @@ -8,12 +8,13 @@ */ package org.eclipse.hawkbit.repository.jpa.model; -/** - * - * Interface defining the action to be performed after entity is - * created/updated. - * - */ -public interface AbstractDescriptorEventVisitor { - void publishEventPostAction(DescriptorEventDetails eventDetails); +import org.eclipse.persistence.descriptors.DescriptorEvent; + +public interface EventAwareEntity { + + public void fireCreateEvent(T t,DescriptorEvent descriptorEvent); + + public void fireUpdateEvent(T t,DescriptorEvent descriptorEvent); + + public void fireDeleteEvent(T t,DescriptorEvent descriptorEvent); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index 5fa2c3bed..fc879aa87 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -1,174 +1,199 @@ -/** - * 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.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.NamedEntityGraphs; -import javax.persistence.NamedSubgraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -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.persistence.annotations.CascadeOnDelete; - -/** - * JPA implementation of {@link Action}. - */ -@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), - @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), - @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) -@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), - @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), - @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) -@Entity -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action { - private static final long serialVersionUID = 1L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) - private JpaDistributionSet distributionSet; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) - private JpaTarget target; - - @Column(name = "active") - private boolean active; - - @Column(name = "action_type", nullable = false) - @Enumerated(EnumType.STRING) - private ActionType actionType; - - @Column(name = "forced_time") - private long forcedTime; - - @Column(name = "status") - private Status status; - - @CascadeOnDelete - @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { - CascadeType.REMOVE }) - private List actionStatus; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) - private JpaRolloutGroup rolloutGroup; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) - private JpaRollout rollout; - - @Override - public DistributionSet getDistributionSet() { - return distributionSet; - } - - @Override - public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = (JpaDistributionSet) distributionSet; - } - - public void setActive(final boolean active) { - this.active = active; - } - - @Override - public Status getStatus() { - return status; - } - - @Override - public void setStatus(final Status status) { - this.status = status; - } - - @Override - public boolean isActive() { - return active; - } - - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - @Override - public ActionType getActionType() { - return actionType; - } - - @Override - public List getActionStatus() { - return actionStatus; - } - - @Override - public void setTarget(final Target target) { - this.target = (JpaTarget) target; - } - - @Override - public Target getTarget() { - return target; - } - - @Override - public long getForcedTime() { - return forcedTime; - } - - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - - @Override - public RolloutGroup getRolloutGroup() { - return rolloutGroup; - } - - public void setRolloutGroup(final RolloutGroup rolloutGroup) { - this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; - } - - @Override - public Rollout getRollout() { - return rollout; - } - - public void setRollout(final Rollout rollout) { - this.rollout = (JpaRollout) rollout; - } - - @Override - public String toString() { - return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; - } - -} +/** + * 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.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.NamedEntityGraphs; +import javax.persistence.NamedSubgraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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.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.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA implementation of {@link Action}. + */ +@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), + @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), + @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) +@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), + @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), + @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) +@Entity +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action,EventAwareEntity { + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) + private JpaDistributionSet distributionSet; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) + private JpaTarget target; + + @Column(name = "active") + private boolean active; + + @Column(name = "action_type", nullable = false) + @Enumerated(EnumType.STRING) + private ActionType actionType; + + @Column(name = "forced_time") + private long forcedTime; + + @Column(name = "status") + private Status status; + + @CascadeOnDelete + @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { + CascadeType.REMOVE }) + private List actionStatus; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) + private JpaRolloutGroup rolloutGroup; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) + private JpaRollout rollout; + + @Override + public DistributionSet getDistributionSet() { + return distributionSet; + } + + @Override + public void setDistributionSet(final DistributionSet distributionSet) { + this.distributionSet = (JpaDistributionSet) distributionSet; + } + + public void setActive(final boolean active) { + this.active = active; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public void setStatus(final Status status) { + this.status = status; + } + + @Override + public boolean isActive() { + return active; + } + + public void setActionType(final ActionType actionType) { + this.actionType = actionType; + } + + @Override + public ActionType getActionType() { + return actionType; + } + + @Override + public List getActionStatus() { + return actionStatus; + } + + @Override + public void setTarget(final Target target) { + this.target = (JpaTarget) target; + } + + @Override + public Target getTarget() { + return target; + } + + @Override + public long getForcedTime() { + return forcedTime; + } + + public void setForcedTime(final long forcedTime) { + this.forcedTime = forcedTime; + } + + @Override + public RolloutGroup getRolloutGroup() { + return rolloutGroup; + } + + public void setRolloutGroup(final RolloutGroup rolloutGroup) { + this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; + } + + @Override + public Rollout getRollout() { + return rollout; + } + + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public String toString() { + return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); + + } + + @Override + public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus(). + post(new ActionPropertyChangeEvent(jpaAction, EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); + + } + + + @Override + public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index 676215424..af8984286 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -1,282 +1,320 @@ -/** - * 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.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; - -import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; -import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.persistence.annotations.CascadeOnDelete; - -/** - * Jpa implementation of {@link DistributionSet}. - * - */ -@Entity -@Table(name = "sp_distribution_set", uniqueConstraints = { - @UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = { - @Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"), - @Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"), - @Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") }) -@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"), - @NamedAttributeNode("tags"), @NamedAttributeNode("type") }) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet { - private static final long serialVersionUID = 1L; - - @Column(name = "required_migration_step") - private boolean requiredMigrationStep; - - @ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) - @JoinTable(name = "sp_ds_module", joinColumns = { - @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = { - @JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) }) - private final Set modules = new HashSet<>(); - - @ManyToMany(targetEntity = JpaDistributionSetTag.class) - @JoinTable(name = "sp_ds_dstag", joinColumns = { - @JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = { - @JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) }) - private Set tags = new HashSet<>(); - - @Column(name = "deleted") - private boolean deleted; - - @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) - private List assignedToTargets; - - @OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY) - private List installedAtTargets; - - @OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY) - private List actions; - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = { - CascadeType.REMOVE }) - @JoinColumn(name = "ds_id", insertable = false, updatable = false) - private final List metadata = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class) - @JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds")) - private DistributionSetType type; - - @Column(name = "complete") - private boolean complete; - - /** - * Default constructor. - */ - public JpaDistributionSet() { - super(); - } - - /** - * Parameterized constructor. - * - * @param name - * of the {@link DistributionSet} - * @param version - * of the {@link DistributionSet} - * @param description - * of the {@link DistributionSet} - * @param type - * of the {@link DistributionSet} - * @param moduleList - * {@link SoftwareModule}s of the {@link DistributionSet} - */ - public JpaDistributionSet(final String name, final String version, final String description, - final DistributionSetType type, final Collection moduleList) { - super(name, version, description); - - this.type = type; - if (moduleList != null) { - moduleList.forEach(this::addModule); - } - if (this.type != null) { - complete = this.type.checkComplete(this); - } - } - - @Override - public Set getTags() { - return tags; - } - - @Override - public boolean isDeleted() { - return deleted; - } - - @Override - public List getMetadata() { - return Collections.unmodifiableList(metadata); - } - - public List getActions() { - return actions; - } - - @Override - public boolean isRequiredMigrationStep() { - return requiredMigrationStep; - } - - @Override - public DistributionSet setDeleted(final boolean deleted) { - this.deleted = deleted; - return this; - } - - @Override - public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) { - requiredMigrationStep = isRequiredMigrationStep; - return this; - } - - public DistributionSet setTags(final Set tags) { - this.tags = tags; - return this; - } - - @Override - public List getAssignedTargets() { - return assignedToTargets; - } - - @Override - public List getInstalledTargets() { - return installedAtTargets; - } - - @Override - public String toString() { - return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision() - + ", getId()=" + getId() + "]"; - } - - @Override - public Set getModules() { - return Collections.unmodifiableSet(modules); - } - - @Override - public boolean addModule(final SoftwareModule softwareModule) { - - // we cannot allow that modules are added without a type defined - if (type == null) { - throw new DistributionSetTypeUndefinedException(); - } - - // check if it is allowed to such a module to this DS type - if (!type.containsModuleType(softwareModule.getType())) { - throw new UnsupportedSoftwareModuleForThisDistributionSetException(); - } - - final Optional found = modules.stream() - .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); - - if (found.isPresent()) { - return false; - } - - final long allready = modules.stream() - .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count(); - - if (allready >= softwareModule.getType().getMaxAssignments()) { - final Optional sameKey = modules.stream() - .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst(); - modules.remove(sameKey.get()); - } - - if (modules.add(softwareModule)) { - complete = type.checkComplete(this); - return true; - } - - return false; - } - - @Override - public boolean removeModule(final SoftwareModule softwareModule) { - final Optional found = modules.stream() - .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); - - if (found.isPresent()) { - modules.remove(found.get()); - complete = type.checkComplete(this); - return true; - } - - return false; - - } - - @Override - public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) { - final Optional result = modules.stream().filter(module -> module.getType().equals(type)) - .findFirst(); - - if (result.isPresent()) { - return result.get(); - } - - return null; - } - - @Override - public DistributionSetType getType() { - return type; - } - - @Override - public void setType(final DistributionSetType type) { - this.type = type; - } - - @Override - public boolean isComplete() { - return complete; - } - -} +/** + * 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.util.ArrayList; +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 javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; +import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; +import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * Jpa implementation of {@link DistributionSet}. + * + */ +@Entity +@Table(name = "sp_distribution_set", uniqueConstraints = { + @UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = { + @Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"), + @Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"), + @Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") }) +@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"), + @NamedAttributeNode("tags"), @NamedAttributeNode("type") }) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet,EventAwareEntity { + private static final long serialVersionUID = 1L; + + private static final String COMPLETE = "complete"; + + @Column(name = "required_migration_step") + private boolean requiredMigrationStep; + + @ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) + @JoinTable(name = "sp_ds_module", joinColumns = { + @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = { + @JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) }) + private final Set modules = new HashSet<>(); + + @ManyToMany(targetEntity = JpaDistributionSetTag.class) + @JoinTable(name = "sp_ds_dstag", joinColumns = { + @JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = { + @JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) }) + private Set tags = new HashSet<>(); + + @Column(name = "deleted") + private boolean deleted; + + @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) + private List assignedToTargets; + + @OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY) + private List installedAtTargets; + + @OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY) + private List actions; + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = { + CascadeType.REMOVE }) + @JoinColumn(name = "ds_id", insertable = false, updatable = false) + private final List metadata = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class) + @JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds")) + private DistributionSetType type; + + @Column(name = "complete") + private boolean complete; + + /** + * Default constructor. + */ + public JpaDistributionSet() { + super(); + } + + /** + * Parameterized constructor. + * + * @param name + * of the {@link DistributionSet} + * @param version + * of the {@link DistributionSet} + * @param description + * of the {@link DistributionSet} + * @param type + * of the {@link DistributionSet} + * @param moduleList + * {@link SoftwareModule}s of the {@link DistributionSet} + */ + public JpaDistributionSet(final String name, final String version, final String description, + final DistributionSetType type, final Collection moduleList) { + super(name, version, description); + + this.type = type; + if (moduleList != null) { + moduleList.forEach(this::addModule); + } + if (this.type != null) { + complete = this.type.checkComplete(this); + } + } + + @Override + public Set getTags() { + return tags; + } + + @Override + public boolean isDeleted() { + return deleted; + } + + @Override + public List getMetadata() { + return Collections.unmodifiableList(metadata); + } + + public List getActions() { + return actions; + } + + @Override + public boolean isRequiredMigrationStep() { + return requiredMigrationStep; + } + + @Override + public DistributionSet setDeleted(final boolean deleted) { + this.deleted = deleted; + return this; + } + + @Override + public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) { + requiredMigrationStep = isRequiredMigrationStep; + return this; + } + + public DistributionSet setTags(final Set tags) { + this.tags = tags; + return this; + } + + @Override + public List getAssignedTargets() { + return assignedToTargets; + } + + @Override + public List getInstalledTargets() { + return installedAtTargets; + } + + @Override + public String toString() { + return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision() + + ", getId()=" + getId() + "]"; + } + + @Override + public Set getModules() { + return Collections.unmodifiableSet(modules); + } + + @Override + public boolean addModule(final SoftwareModule softwareModule) { + + // we cannot allow that modules are added without a type defined + if (type == null) { + throw new DistributionSetTypeUndefinedException(); + } + + // check if it is allowed to such a module to this DS type + if (!type.containsModuleType(softwareModule.getType())) { + throw new UnsupportedSoftwareModuleForThisDistributionSetException(); + } + + final Optional found = modules.stream() + .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); + + if (found.isPresent()) { + return false; + } + + final long allready = modules.stream() + .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count(); + + if (allready >= softwareModule.getType().getMaxAssignments()) { + final Optional sameKey = modules.stream() + .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst(); + modules.remove(sameKey.get()); + } + + if (modules.add(softwareModule)) { + complete = type.checkComplete(this); + return true; + } + + return false; + } + + @Override + public boolean removeModule(final SoftwareModule softwareModule) { + final Optional found = modules.stream() + .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); + + if (found.isPresent()) { + modules.remove(found.get()); + complete = type.checkComplete(this); + return true; + } + + return false; + + } + + @Override + public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) { + final Optional result = modules.stream().filter(module -> module.getType().equals(type)) + .findFirst(); + + if (result.isPresent()) { + return result.get(); + } + + return null; + } + + @Override + public DistributionSetType getType() { + return type; + } + + @Override + public void setType(final DistributionSetType type) { + this.type = type; + } + + @Override + public boolean isComplete() { + return complete; + } + + @Override + public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); + + } + + @Override + public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + final Map.Values> changeSet = EntityPropertyChangeHelper.getChangeSet( + JpaDistributionSet.class, descriptorEvent); + if (changeSet.containsKey(COMPLETE) + && changeSet.get(COMPLETE).getOldValue().equals(false) + && changeSet.get(COMPLETE).getNewValue().equals(true)) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post( + new DistributionCreatedEvent(jpaDistributionSet))); + } + + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); + + } + + @Override + public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 3cbe65717..73d19086d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -1,200 +1,223 @@ -/** - * 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.util.List; - -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -import org.eclipse.hawkbit.repository.jpa.cache.CacheField; -import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys; -import org.eclipse.hawkbit.repository.model.Action.ActionType; -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.TotalTargetCountStatus; - -/** - * JPA implementation of a {@link Rollout}. - * - */ -@Entity -@Table(name = "sp_rollout", indexes = { - @Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "name", "tenant" }, name = "uk_rollout")) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaRollout extends AbstractJpaNamedEntity implements Rollout { - - private static final long serialVersionUID = 1L; - - @OneToMany(targetEntity = JpaRolloutGroup.class) - @JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup")) - private List rolloutGroups; - - @Column(name = "target_filter", length = 1024, nullable = false) - private String targetFilterQuery; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds")) - private JpaDistributionSet distributionSet; - - @Column(name = "status") - private RolloutStatus status = RolloutStatus.CREATING; - - @Column(name = "last_check") - private long lastCheck; - - @Column(name = "action_type", nullable = false) - @Enumerated(EnumType.STRING) - private ActionType actionType = ActionType.FORCED; - - @Column(name = "forced_time") - private long forcedTime; - - @Column(name = "total_targets") - private long totalTargets; - - @Transient - @CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL) - private int rolloutGroupsTotal; - - @Transient - @CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED) - private int rolloutGroupsCreated; - - @Transient - private transient TotalTargetCountStatus totalTargetCountStatus; - - @Override - public DistributionSet getDistributionSet() { - return distributionSet; - } - - @Override - public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = (JpaDistributionSet) distributionSet; - } - - @Override - public List getRolloutGroups() { - return rolloutGroups; - } - - public void setRolloutGroups(final List rolloutGroups) { - this.rolloutGroups = rolloutGroups; - } - - @Override - public String getTargetFilterQuery() { - return targetFilterQuery; - } - - @Override - public void setTargetFilterQuery(final String targetFilterQuery) { - this.targetFilterQuery = targetFilterQuery; - } - - @Override - public RolloutStatus getStatus() { - return status; - } - - public void setStatus(final RolloutStatus status) { - this.status = status; - } - - public long getLastCheck() { - return lastCheck; - } - - public void setLastCheck(final long lastCheck) { - this.lastCheck = lastCheck; - } - - @Override - public ActionType getActionType() { - return actionType; - } - - @Override - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - @Override - public long getForcedTime() { - return forcedTime; - } - - @Override - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - - @Override - public long getTotalTargets() { - return totalTargets; - } - - public void setTotalTargets(final long totalTargets) { - this.totalTargets = totalTargets; - } - - public int getRolloutGroupsTotal() { - return rolloutGroupsTotal; - } - - public void setRolloutGroupsTotal(final int rolloutGroupsTotal) { - this.rolloutGroupsTotal = rolloutGroupsTotal; - } - - @Override - public int getRolloutGroupsCreated() { - return rolloutGroupsCreated; - } - - public void setRolloutGroupsCreated(final int rolloutGroupsCreated) { - this.rolloutGroupsCreated = rolloutGroupsCreated; - } - - @Override - public TotalTargetCountStatus getTotalTargetCountStatus() { - if (totalTargetCountStatus == null) { - totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); - } - return totalTargetCountStatus; - } - - public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { - this.totalTargetCountStatus = totalTargetCountStatus; - } - - @Override - public String toString() { - return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery - + ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck - + ", getName()=" + getName() + ", getId()=" + getId() + "]"; - } - -} +/** + * 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.util.List; + +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; + +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.AfterTransactionCommitExecutorHolder; +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.ActionType; +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.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA implementation of a {@link Rollout}. + * + */ +@Entity +@Table(name = "sp_rollout", indexes = { + @Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "name", "tenant" }, name = "uk_rollout")) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventAwareEntity { + + private static final long serialVersionUID = 1L; + + @OneToMany(targetEntity = JpaRolloutGroup.class) + @JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup")) + private List rolloutGroups; + + @Column(name = "target_filter", length = 1024, nullable = false) + private String targetFilterQuery; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds")) + private JpaDistributionSet distributionSet; + + @Column(name = "status") + private RolloutStatus status = RolloutStatus.CREATING; + + @Column(name = "last_check") + private long lastCheck; + + @Column(name = "action_type", nullable = false) + @Enumerated(EnumType.STRING) + private ActionType actionType = ActionType.FORCED; + + @Column(name = "forced_time") + private long forcedTime; + + @Column(name = "total_targets") + private long totalTargets; + + @Transient + @CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL) + private int rolloutGroupsTotal; + + @Transient + @CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED) + private int rolloutGroupsCreated; + + @Transient + private transient TotalTargetCountStatus totalTargetCountStatus; + + @Override + public DistributionSet getDistributionSet() { + return distributionSet; + } + + @Override + public void setDistributionSet(final DistributionSet distributionSet) { + this.distributionSet = (JpaDistributionSet) distributionSet; + } + + @Override + public List getRolloutGroups() { + return rolloutGroups; + } + + public void setRolloutGroups(final List rolloutGroups) { + this.rolloutGroups = rolloutGroups; + } + + @Override + public String getTargetFilterQuery() { + return targetFilterQuery; + } + + @Override + public void setTargetFilterQuery(final String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + } + + @Override + public RolloutStatus getStatus() { + return status; + } + + public void setStatus(final RolloutStatus status) { + this.status = status; + } + + public long getLastCheck() { + return lastCheck; + } + + public void setLastCheck(final long lastCheck) { + this.lastCheck = lastCheck; + } + + @Override + public ActionType getActionType() { + return actionType; + } + + @Override + public void setActionType(final ActionType actionType) { + this.actionType = actionType; + } + + @Override + public long getForcedTime() { + return forcedTime; + } + + @Override + public void setForcedTime(final long forcedTime) { + this.forcedTime = forcedTime; + } + + @Override + public long getTotalTargets() { + return totalTargets; + } + + public void setTotalTargets(final long totalTargets) { + this.totalTargets = totalTargets; + } + + public int getRolloutGroupsTotal() { + return rolloutGroupsTotal; + } + + public void setRolloutGroupsTotal(final int rolloutGroupsTotal) { + this.rolloutGroupsTotal = rolloutGroupsTotal; + } + + @Override + public int getRolloutGroupsCreated() { + return rolloutGroupsCreated; + } + + public void setRolloutGroupsCreated(final int rolloutGroupsCreated) { + this.rolloutGroupsCreated = rolloutGroupsCreated; + } + + @Override + public TotalTargetCountStatus getTotalTargetCountStatus() { + if (totalTargetCountStatus == null) { + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + } + return totalTargetCountStatus; + } + + public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { + this.totalTargetCountStatus = totalTargetCountStatus; + } + + @Override + public String toString() { + return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery + + ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck + + ", getName()=" + getName() + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + + } + + @Override + public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). + post(new RolloutPropertyChangeEvent(jpaRollout, EntityPropertyChangeHelper.getChangeSet( + Rollout.class, descriptorEvent)))); + + } + + @Override + public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java index 79da6630a..6456a3e93 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -1,239 +1,261 @@ -/** - * 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.util.ArrayList; -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; - -/** - * JPA entity definition of persisting a group of an rollout. - * - */ -@Entity -@Table(name = "sp_rolloutgroup", indexes = { - @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup { - - private static final long serialVersionUID = 1L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) - private JpaRollout rollout; - - @Column(name = "status") - private RolloutGroupStatus status = RolloutGroupStatus.READY; - - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class) - @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) - private final List rolloutTargetGroup = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY) - private JpaRolloutGroup parent; - - @Column(name = "success_condition", nullable = false) - private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; - - @Column(name = "success_condition_exp", length = 512, nullable = false) - private String successConditionExp; - - @Column(name = "success_action", nullable = false) - private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; - - @Column(name = "success_action_exp", length = 512, nullable = false) - private String successActionExp; - - @Column(name = "error_condition") - private RolloutGroupErrorCondition errorCondition; - - @Column(name = "error_condition_exp", length = 512) - private String errorConditionExp; - - @Column(name = "error_action") - private RolloutGroupErrorAction errorAction; - - @Column(name = "error_action_exp", length = 512) - private String errorActionExp; - - @Column(name = "total_targets") - private long totalTargets; - - @Transient - private transient TotalTargetCountStatus totalTargetCountStatus; - - @Override - public Rollout getRollout() { - return rollout; - } - - @Override - public void setRollout(final Rollout rollout) { - this.rollout = (JpaRollout) rollout; - } - - @Override - public RolloutGroupStatus getStatus() { - return status; - } - - @Override - public void setStatus(final RolloutGroupStatus status) { - this.status = status; - } - - public List getRolloutTargetGroup() { - return rolloutTargetGroup; - } - - @Override - public RolloutGroup getParent() { - return parent; - } - - public void setParent(final RolloutGroup parent) { - this.parent = (JpaRolloutGroup) parent; - } - - @Override - public RolloutGroupSuccessCondition getSuccessCondition() { - return successCondition; - } - - @Override - public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - successCondition = finishCondition; - } - - @Override - public String getSuccessConditionExp() { - return successConditionExp; - } - - @Override - public void setSuccessConditionExp(final String finishExp) { - successConditionExp = finishExp; - } - - @Override - public RolloutGroupErrorCondition getErrorCondition() { - return errorCondition; - } - - @Override - public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { - this.errorCondition = errorCondition; - } - - @Override - public String getErrorConditionExp() { - return errorConditionExp; - } - - @Override - public void setErrorConditionExp(final String errorExp) { - errorConditionExp = errorExp; - } - - @Override - public RolloutGroupErrorAction getErrorAction() { - return errorAction; - } - - @Override - public void setErrorAction(final RolloutGroupErrorAction errorAction) { - this.errorAction = errorAction; - } - - @Override - public String getErrorActionExp() { - return errorActionExp; - } - - @Override - public void setErrorActionExp(final String errorActionExp) { - this.errorActionExp = errorActionExp; - } - - @Override - public RolloutGroupSuccessAction getSuccessAction() { - return successAction; - } - - @Override - public String getSuccessActionExp() { - return successActionExp; - } - - @Override - public long getTotalTargets() { - return totalTargets; - } - - public void setTotalTargets(final long totalTargets) { - this.totalTargets = totalTargets; - } - - public void setSuccessAction(final RolloutGroupSuccessAction successAction) { - this.successAction = successAction; - } - - public void setSuccessActionExp(final String successActionExp) { - this.successActionExp = successActionExp; - } - - /** - * @return the totalTargetCountStatus - */ - @Override - public TotalTargetCountStatus getTotalTargetCountStatus() { - if (totalTargetCountStatus == null) { - totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); - } - return totalTargetCountStatus; - } - - /** - * @param totalTargetCountStatus - * the totalTargetCountStatus to set - */ - @Override - public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { - this.totalTargetCountStatus = totalTargetCountStatus; - } - - @Override - public String toString() { - return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup - + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp - + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() - + ", getId()=" + getId() + "]"; - } - -} +/** + * 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.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; + +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA entity definition of persisting a group of an rollout. + * + */ +@Entity +@Table(name = "sp_rolloutgroup", indexes = { + @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup,EventAwareEntity { + + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) + private JpaRollout rollout; + + @Column(name = "status") + private RolloutGroupStatus status = RolloutGroupStatus.READY; + + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class) + @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) + private final List rolloutTargetGroup = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + private JpaRolloutGroup parent; + + @Column(name = "success_condition", nullable = false) + private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; + + @Column(name = "success_condition_exp", length = 512, nullable = false) + private String successConditionExp; + + @Column(name = "success_action", nullable = false) + private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; + + @Column(name = "success_action_exp", length = 512, nullable = false) + private String successActionExp; + + @Column(name = "error_condition") + private RolloutGroupErrorCondition errorCondition; + + @Column(name = "error_condition_exp", length = 512) + private String errorConditionExp; + + @Column(name = "error_action") + private RolloutGroupErrorAction errorAction; + + @Column(name = "error_action_exp", length = 512) + private String errorActionExp; + + @Column(name = "total_targets") + private long totalTargets; + + @Transient + private transient TotalTargetCountStatus totalTargetCountStatus; + + @Override + public Rollout getRollout() { + return rollout; + } + + @Override + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public RolloutGroupStatus getStatus() { + return status; + } + + @Override + public void setStatus(final RolloutGroupStatus status) { + this.status = status; + } + + public List getRolloutTargetGroup() { + return rolloutTargetGroup; + } + + @Override + public RolloutGroup getParent() { + return parent; + } + + public void setParent(final RolloutGroup parent) { + this.parent = (JpaRolloutGroup) parent; + } + + @Override + public RolloutGroupSuccessCondition getSuccessCondition() { + return successCondition; + } + + @Override + public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { + successCondition = finishCondition; + } + + @Override + public String getSuccessConditionExp() { + return successConditionExp; + } + + @Override + public void setSuccessConditionExp(final String finishExp) { + successConditionExp = finishExp; + } + + @Override + public RolloutGroupErrorCondition getErrorCondition() { + return errorCondition; + } + + @Override + public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { + this.errorCondition = errorCondition; + } + + @Override + public String getErrorConditionExp() { + return errorConditionExp; + } + + @Override + public void setErrorConditionExp(final String errorExp) { + errorConditionExp = errorExp; + } + + @Override + public RolloutGroupErrorAction getErrorAction() { + return errorAction; + } + + @Override + public void setErrorAction(final RolloutGroupErrorAction errorAction) { + this.errorAction = errorAction; + } + + @Override + public String getErrorActionExp() { + return errorActionExp; + } + + @Override + public void setErrorActionExp(final String errorActionExp) { + this.errorActionExp = errorActionExp; + } + + @Override + public RolloutGroupSuccessAction getSuccessAction() { + return successAction; + } + + @Override + public String getSuccessActionExp() { + return successActionExp; + } + + @Override + public long getTotalTargets() { + return totalTargets; + } + + public void setTotalTargets(final long totalTargets) { + this.totalTargets = totalTargets; + } + + public void setSuccessAction(final RolloutGroupSuccessAction successAction) { + this.successAction = successAction; + } + + public void setSuccessActionExp(final String successActionExp) { + this.successActionExp = successActionExp; + } + + /** + * @return the totalTargetCountStatus + */ + @Override + public TotalTargetCountStatus getTotalTargetCountStatus() { + if (totalTargetCountStatus == null) { + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + } + return totalTargetCountStatus; + } + + /** + * @param totalTargetCountStatus + * the totalTargetCountStatus to set + */ + @Override + public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { + this.totalTargetCountStatus = totalTargetCountStatus; + } + + @Override + public String toString() { + return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup + + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp + + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() + + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + + } + + @Override + public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). + post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, + EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); + } + + @Override + public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index 183405470..f6a2b8346 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -1,234 +1,257 @@ -/** - * 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.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -import org.eclipse.hawkbit.im.authentication.SpPermission; -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; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.persistence.annotations.CascadeOnDelete; -import org.springframework.data.domain.Persistable; - -/** - * JPA implementation of {@link Target}. - * - */ -@Entity -@Table(name = "sp_target", indexes = { - @Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"), - @Index(name = "sp_idx_target_02", columnList = "tenant,name"), - @Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"), - @Index(name = "sp_idx_target_04", columnList = "tenant,created_at"), - @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "controller_id", "tenant" }, name = "uk_tenant_controller_id")) -@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"), - @NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") }) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target { - private static final long serialVersionUID = 1L; - - @Column(name = "controller_id", length = 64) - @Size(min = 1) - @NotNull - private String controllerId; - - @Transient - private boolean entityNew; - - @ManyToMany(targetEntity = JpaTargetTag.class) - @JoinTable(name = "sp_target_target_tag", joinColumns = { - @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = { - @JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) }) - private Set tags = new HashSet<>(); - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { - CascadeType.REMOVE }, targetEntity = JpaAction.class) - @JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ")) - private final List actions = new ArrayList<>(); - - @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class) - @JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds")) - private JpaDistributionSet assignedDistributionSet; - - @CascadeOnDelete - @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class) - @PrimaryKeyJoinColumn - private JpaTargetInfo targetInfo; - - /** - * the security token of the target which allows if enabled to authenticate - * with this security token. - */ - @Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128) - private String securityToken; - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) - @JoinColumn(name = "target_Id", insertable = false, updatable = false) - private final List rolloutTargetGroup = new ArrayList<>(); - - /** - * Constructor. - * - * @param controllerId - * 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); - this.securityToken = securityToken; - targetInfo = new JpaTargetInfo(this); - } - - /** - * empty constructor for JPA. - */ - JpaTarget() { - controllerId = null; - securityToken = null; - } - - @Override - public DistributionSet getAssignedDistributionSet() { - return assignedDistributionSet; - } - - @Override - public String getControllerId() { - return controllerId; - } - - @Override - public Set getTags() { - return tags; - } - - public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) { - this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet; - } - - public void setControllerId(final String controllerId) { - this.controllerId = controllerId; - } - - public void setTags(final Set tags) { - this.tags = tags; - } - - @Override - public List getActions() { - return actions; - } - - @Override - @Transient - public boolean isNew() { - return entityNew; - } - - /** - * @param isNew - * the isNew to set - */ - public void setNew(final boolean entityNew) { - this.entityNew = entityNew; - } - - /** - * @return the targetInfo - */ - @Override - public TargetInfo getTargetInfo() { - return targetInfo; - } - - /** - * @param targetInfo - * the targetInfo to set - */ - public void setTargetInfo(final TargetInfo targetInfo) { - this.targetInfo = (JpaTargetInfo) targetInfo; - } - - /** - * @return the securityToken if the current security context contains the - * necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN} - * or the current context is executed as system code, otherwise - * {@code null}. - */ - @Override - public String getSecurityToken() { - if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode() - || SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) { - return securityToken; - } - return null; - } - - /** - * @param securityToken - * the securityToken to set - */ - public void setSecurityToken(final String securityToken) { - this.securityToken = securityToken; - } - - @Override - public String toString() { - return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]"; - } - -} +/** + * 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.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; +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.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +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; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.springframework.data.domain.Persistable; + +/** + * JPA implementation of {@link Target}. + * + */ +@Entity +@Table(name = "sp_target", indexes = { + @Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"), + @Index(name = "sp_idx_target_02", columnList = "tenant,name"), + @Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"), + @Index(name = "sp_idx_target_04", columnList = "tenant,created_at"), + @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "controller_id", "tenant" }, name = "uk_tenant_controller_id")) +@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"), + @NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") }) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { + private static final long serialVersionUID = 1L; + + @Column(name = "controller_id", length = 64) + @Size(min = 1) + @NotNull + private String controllerId; + + @Transient + private boolean entityNew; + + @ManyToMany(targetEntity = JpaTargetTag.class) + @JoinTable(name = "sp_target_target_tag", joinColumns = { + @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = { + @JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) }) + private Set tags = new HashSet<>(); + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { + CascadeType.REMOVE }, targetEntity = JpaAction.class) + @JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ")) + private final List actions = new ArrayList<>(); + + @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class) + @JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds")) + private JpaDistributionSet assignedDistributionSet; + + @CascadeOnDelete + @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class) + @PrimaryKeyJoinColumn + private JpaTargetInfo targetInfo; + + /** + * the security token of the target which allows if enabled to authenticate + * with this security token. + */ + @Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128) + private String securityToken; + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) + @JoinColumn(name = "target_Id", insertable = false, updatable = false) + private final List rolloutTargetGroup = new ArrayList<>(); + + /** + * Constructor. + * + * @param controllerId + * 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); + this.securityToken = securityToken; + targetInfo = new JpaTargetInfo(this); + } + + /** + * empty constructor for JPA. + */ + JpaTarget() { + controllerId = null; + securityToken = null; + } + + @Override + public DistributionSet getAssignedDistributionSet() { + return assignedDistributionSet; + } + + @Override + public String getControllerId() { + return controllerId; + } + + @Override + public Set getTags() { + return tags; + } + + public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) { + this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet; + } + + public void setControllerId(final String controllerId) { + this.controllerId = controllerId; + } + + public void setTags(final Set tags) { + this.tags = tags; + } + + @Override + public List getActions() { + return actions; + } + + @Override + @Transient + public boolean isNew() { + return entityNew; + } + + /** + * @param isNew + * the isNew to set + */ + public void setNew(final boolean entityNew) { + this.entityNew = entityNew; + } + + /** + * @return the targetInfo + */ + @Override + public TargetInfo getTargetInfo() { + return targetInfo; + } + + /** + * @param targetInfo + * the targetInfo to set + */ + public void setTargetInfo(final TargetInfo targetInfo) { + this.targetInfo = (JpaTargetInfo) targetInfo; + } + + /** + * @return the securityToken if the current security context contains the + * necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN} + * or the current context is executed as system code, otherwise + * {@code null}. + */ + @Override + public String getSecurityToken() { + if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode() + || SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) { + return securityToken; + } + return null; + } + + /** + * @param securityToken + * the securityToken to set + */ + @Override + public void setSecurityToken(final String securityToken) { + this.securityToken = securityToken; + } + + @Override + public String toString() { + return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); + } + + @Override + public void fireUpdateEvent(final JpaTarget jpaTarget,final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); + + } + + @Override + public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { + + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index 0606def4f..a21c7547f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -1,324 +1,344 @@ -/** - * 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.net.URI; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.persistence.CascadeType; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Id; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapsId; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Transient; - -import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; -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.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.eclipse.persistence.annotations.CascadeOnDelete; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Persistable; - -/** - * A table which contains all the information inserted, updated by the - * controller itself. So this entity does not provide audit information because - * changes on this entity are mostly only done by controller requests. That's - * the reason that we store these information in a separated table so we don't - * modifying the {@link Target} itself when a controller reports it's - * {@link #lastTargetQuery} for example. - * - */ -@Table(name = "sp_target_info", indexes = { - @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) -@Entity -public class JpaTargetInfo implements Persistable, TargetInfo { - private static final long serialVersionUID = 1L; - - private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); - - @Id - private Long targetId; - - @Transient - private boolean entityNew; - - @CascadeOnDelete - @OneToOne(cascade = { CascadeType.MERGE, - CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class) - @JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ")) - @MapsId - private JpaTarget target; - - @Column(name = "address", length = 512) - private String address; - - @Column(name = "last_target_query") - private Long lastTargetQuery; - - @Column(name = "install_date") - private Long installationDate; - - @Column(name = "update_status", nullable = false, length = 255) - @Enumerated(EnumType.STRING) - private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN; - - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds")) - private JpaDistributionSet installedDistributionSet; - - /** - * Read only on management API. Are commited by controller. - */ - @ElementCollection - @Column(name = "attribute_value", length = 128) - @MapKeyColumn(name = "attribute_key", nullable = false, length = 32) - @CollectionTable(name = "sp_target_attributes", joinColumns = { - @JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target")) - - private final Map controllerAttributes = Collections.synchronizedMap(new HashMap()); - - // set default request controller attributes to true, because we want to - // request them the first - // time - @Column(name = "request_controller_attributes", nullable = false) - private boolean requestControllerAttributes = true; - - /** - * Constructor for {@link TargetStatus}. - * - * @param target - * related to this status. - */ - public JpaTargetInfo(final JpaTarget target) { - this.target = target; - targetId = target.getId(); - } - - JpaTargetInfo() { - target = null; - targetId = null; - } - - @Override - public Long getId() { - return targetId; - } - - @Override - @Transient - public boolean isNew() { - return entityNew; - } - - /** - * @param isNew - * the isNew to set - */ - public void setNew(final boolean entityNew) { - this.entityNew = entityNew; - } - - /** - * @return the ipAddress - */ - @Override - public URI getAddress() { - if (address == null) { - return null; - } - try { - return URI.create(address); - } catch (final IllegalArgumentException e) { - LOG.warn("Invalid address provided. Cloud not be configured to URI", e); - return null; - } - } - - /** - * @param address - * the target address to set - * - * @throws IllegalArgumentException - * If the given string violates RFC 2396 - */ - @Override - public void setAddress(final String address) { - // check if this is a real URI - if (address != null) { - try { - URI.create(address); - } catch (final IllegalArgumentException e) { - throw new InvalidTargetAddressException( - "The given address " + address + " violates the RFC-2396 specification", e); - } - } - - this.address = address; - } - - public Long getTargetId() { - return targetId; - } - - public void setTargetId(final Long targetId) { - this.targetId = targetId; - } - - @Override - public Target getTarget() { - return target; - } - - public void setTarget(final JpaTarget target) { - this.target = target; - } - - @Override - public Long getLastTargetQuery() { - return lastTargetQuery; - } - - public void setLastTargetQuery(final Long lastTargetQuery) { - this.lastTargetQuery = lastTargetQuery; - } - - public void setRequestControllerAttributes(final boolean requestControllerAttributes) { - this.requestControllerAttributes = requestControllerAttributes; - } - - @Override - public Map getControllerAttributes() { - return controllerAttributes; - } - - @Override - public boolean isRequestControllerAttributes() { - return requestControllerAttributes; - } - - @Override - public Long getInstallationDate() { - return installationDate; - } - - public void setInstallationDate(final Long installationDate) { - this.installationDate = installationDate; - } - - @Override - public TargetUpdateStatus getUpdateStatus() { - return updateStatus; - } - - public void setUpdateStatus(final TargetUpdateStatus updateStatus) { - this.updateStatus = updateStatus; - } - - @Override - public DistributionSet getInstalledDistributionSet() { - return installedDistributionSet; - } - - public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) { - this.installedDistributionSet = installedDistributionSet; - } - - /** - * @return the poll time which holds the last poll time of the target, the - * next poll time and the overdue time. In case the - * {@link #lastTargetQuery} is not set e.g. the target never polled - * before this method returns {@code null} - */ - @Override - public PollStatus getPollStatus() { - if (lastTargetQuery == null) { - return null; - } - return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> { - final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder - .getInstance().getTenantConfigurationManagement() - .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); - final Duration overdueTime = DurationHelper.formattedStringToDuration( - TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() - .getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) - .getValue()); - final LocalDateTime currentDate = LocalDateTime.now(); - final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), - ZoneId.systemDefault()); - final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); - final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); - return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); - }); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((target == null) ? 0 : target.hashCode()); - result = prime * result + ((targetId == null) ? 0 : targetId.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof TargetInfo)) { - return false; - } - final JpaTargetInfo other = (JpaTargetInfo) obj; - if (target == null) { - if (other.target != null) { - return false; - } - } else if (!target.equals(other.target)) { - return false; - } - if (targetId == null) { - if (other.targetId != null) { - return false; - } - } else if (!targetId.equals(other.targetId)) { - return false; - } - return true; - } -} +/** + * 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.net.URI; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapsId; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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.tenancy.configuration.DurationHelper; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Persistable; + +/** + * A table which contains all the information inserted, updated by the + * controller itself. So this entity does not provide audit information because + * changes on this entity are mostly only done by controller requests. That's + * the reason that we store these information in a separated table so we don't + * modifying the {@link Target} itself when a controller reports it's + * {@link #lastTargetQuery} for example. + * + */ +@Table(name = "sp_target_info", indexes = { + @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) +@Entity +@EntityListeners(EntityPropertyChangeListener.class) +public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); + + @Id + private Long targetId; + + @Transient + private boolean entityNew; + + @CascadeOnDelete + @OneToOne(cascade = { CascadeType.MERGE, + CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class) + @JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ")) + @MapsId + private JpaTarget target; + + @Column(name = "address", length = 512) + private String address; + + @Column(name = "last_target_query") + private Long lastTargetQuery; + + @Column(name = "install_date") + private Long installationDate; + + @Column(name = "update_status", nullable = false, length = 255) + @Enumerated(EnumType.STRING) + private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN; + + @ManyToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds")) + private JpaDistributionSet installedDistributionSet; + + /** + * Read only on management API. Are commited by controller. + */ + @ElementCollection + @Column(name = "attribute_value", length = 128) + @MapKeyColumn(name = "attribute_key", nullable = false, length = 32) + @CollectionTable(name = "sp_target_attributes", joinColumns = { + @JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target")) + + private final Map controllerAttributes = Collections.synchronizedMap(new HashMap()); + + // set default request controller attributes to true, because we want to + // request them the first + // time + @Column(name = "request_controller_attributes", nullable = false) + private boolean requestControllerAttributes = true; + + /** + * Constructor for {@link TargetStatus}. + * + * @param target + * related to this status. + */ + public JpaTargetInfo(final JpaTarget target) { + this.target = target; + targetId = target.getId(); + } + + JpaTargetInfo() { + target = null; + targetId = null; + } + + @Override + public Long getId() { + return targetId; + } + + @Override + @Transient + public boolean isNew() { + return entityNew; + } + + /** + * @param isNew + * the isNew to set + */ + public void setNew(final boolean entityNew) { + this.entityNew = entityNew; + } + + /** + * @return the ipAddress + */ + @Override + public URI getAddress() { + if (address == null) { + return null; + } + try { + return URI.create(address); + } catch (final IllegalArgumentException e) { + LOG.warn("Invalid address provided. Cloud not be configured to URI", e); + return null; + } + } + + /** + * @param address + * the target address to set + * + * @throws IllegalArgumentException + * If the given string violates RFC 2396 + */ + @Override + public void setAddress(final String address) { + // check if this is a real URI + if (address != null) { + try { + URI.create(address); + } catch (final IllegalArgumentException e) { + throw new InvalidTargetAddressException( + "The given address " + address + " violates the RFC-2396 specification", e); + } + } + + this.address = address; + } + + public Long getTargetId() { + return targetId; + } + + public void setTargetId(final Long targetId) { + this.targetId = targetId; + } + + @Override + public Target getTarget() { + return target; + } + + public void setTarget(final JpaTarget target) { + this.target = target; + } + + @Override + public Long getLastTargetQuery() { + return lastTargetQuery; + } + + public void setLastTargetQuery(final Long lastTargetQuery) { + this.lastTargetQuery = lastTargetQuery; + } + + public void setRequestControllerAttributes(final boolean requestControllerAttributes) { + this.requestControllerAttributes = requestControllerAttributes; + } + + @Override + public Map getControllerAttributes() { + return controllerAttributes; + } + + @Override + public boolean isRequestControllerAttributes() { + return requestControllerAttributes; + } + + @Override + public Long getInstallationDate() { + return installationDate; + } + + public void setInstallationDate(final Long installationDate) { + this.installationDate = installationDate; + } + + @Override + public TargetUpdateStatus getUpdateStatus() { + return updateStatus; + } + + public void setUpdateStatus(final TargetUpdateStatus updateStatus) { + this.updateStatus = updateStatus; + } + + @Override + public DistributionSet getInstalledDistributionSet() { + return installedDistributionSet; + } + + public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) { + this.installedDistributionSet = installedDistributionSet; + } + + /** + * @return the poll time which holds the last poll time of the target, the + * next poll time and the overdue time. In case the + * {@link #lastTargetQuery} is not set e.g. the target never polled + * before this method returns {@code null} + */ + @Override + public PollStatus getPollStatus() { + if (lastTargetQuery == null) { + return null; + } + return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> { + final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder + .getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); + final Duration overdueTime = DurationHelper.formattedStringToDuration( + TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) + .getValue()); + final LocalDateTime currentDate = LocalDateTime.now(); + final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), + ZoneId.systemDefault()); + final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); + final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); + return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); + }); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((target == null) ? 0 : target.hashCode()); + result = prime * result + ((targetId == null) ? 0 : targetId.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof TargetInfo)) { + return false; + } + final JpaTargetInfo other = (JpaTargetInfo) obj; + if (target == null) { + if (other.target != null) { + return false; + } + } else if (!target.equals(other.target)) { + return false; + } + if (targetId == null) { + if (other.targetId != null) { + return false; + } + } else if (!targetId.equals(other.targetId)) { + return false; + } + return true; + } + + @Override + public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo,final DescriptorEvent descriptorEvent) { + // there is no target info created event + } + + @Override + public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); + } + + @Override + public void fireDeleteEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + } +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java new file mode 100644 index 000000000..71c374c5f --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.model.helper; + +import java.util.Map; +import java.util.stream.Collectors; + +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity; +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; + +public class EntityPropertyChangeHelper { + + + public static Map.Values> getChangeSet( + final Class clazz, final DescriptorEvent event) { + final T rolloutGroup = clazz.cast(event.getObject()); + 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 AbstractPropertyChangeEvent( + rolloutGroup, null).new Values(record + .getOldValue(), record.getNewValue()))); + } + +} From bf28a8dde8764522c00085614b79b85da84216a0 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Thu, 28 Jul 2016 14:07:19 +0200 Subject: [PATCH 03/28] Fixed the issue for metadata not getting updated and also the refresh of page not displaying the distribution details in deployment and distribution view. Signed-off-by: Gaurav --- .../repository/DistributionSetManagement.java | 1206 +++++++-------- .../repository/SoftwareManagement.java | 990 ++++++------ .../jpa/JpaDistributionSetManagement.java | 61 +- .../repository/jpa/JpaSoftwareManagement.java | 1335 +++++++++-------- .../AbstractTableDetailsLayout.java | 1 - .../DistributionSetMetadatadetailslayout.java | 112 +- .../SoftwareModuleMetadatadetailslayout.java | 4 +- .../dstable/DistributionSetDetails.java | 65 +- .../dstable/DsMetadataPopupLayout.java | 32 +- .../ui/distributions/event/MetadataEvent.java | 9 +- .../DistributionAddUpdateWindowLayout.java | 10 +- .../dstable/DistributionDetails.java | 69 +- 12 files changed, 1936 insertions(+), 1958 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index a2e7e5213..f7566b86b 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -1,598 +1,608 @@ -/** - * 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; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetFilter; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Tag; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.security.access.prepost.PreAuthorize; - -/** - * Management service for {@link DistributionSet}s. - * - */ -public interface DistributionSetManagement { - - // TODO rename/document the whole with details thing (document what the - // details are and maybe find a better name, e.g. with dependencies?) - - /** - * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. - * - * @param ds - * to assign and update - * @param softwareModules - * to get assigned - * @return the updated {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet assignSoftwareModules(@NotNull DistributionSet ds, Set softwareModules); - - /** - * Assign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s. - * - * @param dsIds - * to assign for - * @param tag - * to assign - * @return list of assigned ds - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List assignTag(@NotEmpty Collection dsIds, @NotNull DistributionSetTag tag); - - /** - * Count all {@link DistributionSet}s in the repository that are not marked - * as deleted. - * - * @return number of {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetsAll(); - - /** - * Count all {@link DistributionSet}s in the repository that are not marked - * as deleted. - * - * @param type - * to look for - * - * @return number of {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetsByType(@NotNull DistributionSetType type); - - /** - * @return number of {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetTypesAll(); - - /** - * Creates a new {@link DistributionSet}. - * - * @param dSet - * {@link DistributionSet} to be created - * @return the new persisted {@link DistributionSet} - * - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - DistributionSet createDistributionSet(@NotNull DistributionSet dSet); - - /** - * creates a list of distribution set meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created distribution set meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List createDistributionSetMetadata(@NotEmpty Collection metadata); - - /** - * creates or updates a single distribution set meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created distribution set meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetMetadata createDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); - - /** - * Creates multiple {@link DistributionSet}s. - * - * @param distributionSets - * to be created - * @return the new {@link DistributionSet}s - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createDistributionSets(@NotNull Collection distributionSets); - - /** - * Creates new {@link DistributionSetType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - DistributionSetType createDistributionSetType(@NotNull DistributionSetType type); - - /** - * Creates multiple {@link DistributionSetType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createDistributionSetTypes(@NotNull Collection types); - - /** - *

- * {@link DistributionSet} can be deleted/erased from the repository if they - * have never been assigned to any {@link UpdateAction} or {@link Target}. - *

- * - *

- * If they have been assigned that need to be marked as deleted which as a - * result means that they cannot be assigned anymore to any targets. (define - * e.g. findByDeletedFalse()) - *

- * - * @param set - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSet(@NotNull DistributionSet set); - - /** - * Deleted {@link DistributionSet}s by their IDs. That is either a soft - * delete of the entities have been linked to an {@link UpdateAction} before - * or a hard delete if not. - * - * @param distributionSetIDs - * to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSet(@NotEmpty Long... distributionSetIDs); - - /** - * deletes a distribution set meta data entry. - * - * @param id - * the ID of the distribution set meta data to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key); - - /** - * Deletes or mark as delete in case the type is in use. - * - * @param type - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSetType(@NotNull DistributionSetType type); - - /** - * retrieves the distribution set for a given action. - * - * @param action - * the action associated with the distribution set - * @return the distribution set which is associated with the action - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByAction(@NotNull Action action); - - /** - * Find {@link DistributionSet} based on given ID without details, e.g. - * {@link DistributionSet#getAgentHub()}. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetById(@NotNull Long distid); - - /** - * Find {@link DistributionSet} based on given ID including (lazy loaded) - * details, e.g. {@link DistributionSet#getAgentHub()}. - * - * Note: for performance reasons it is recommended to use - * {@link #findDistributionSetById(Long)} if details are not necessary. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByIdWithDetails(@NotNull Long distid); - - /** - * Find distribution set by name and version. - * - * @param distributionName - * name of {@link DistributionSet}; case insensitive - * @param version - * version of {@link DistributionSet} - * @return the page with the found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByNameAndVersion(@NotEmpty String distributionName, @NotEmpty String version); - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, - @NotNull Pageable pageable); - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param rsqlParam - * rsql query string - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, - @NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Retrieves {@link DistributionSet} List for overview purposes (no - * {@link SoftwareModule}s and {@link DistributionSetTag}s). - * - * Please use {@link #findDistributionSetListWithDetails(Iterable)} if - * details are required. - * - * @param dist - * List of {@link DistributionSet} IDs to be found - * @return the found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - List findDistributionSetsAll(Collection dist); - - // TODO discuss: use enum instead of the true,false,null switch ? - /** - * finds all {@link DistributionSet}s. - * - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @param complete - * to true for returning only completed distribution - * sets or false for only incomplete ones nor - * null to return both. - * @param complete - * set to if false incomplete DS should also be - * shown. - * - * - * @return all found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsByDeletedAndOrCompleted(@NotNull Pageable pageReq, Boolean deleted, - Boolean complete); - - /** - * finds all {@link DistributionSet}s. - * - * @param rsqlParam - * rsql query string - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @return all found {@link DistributionSet}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsAll(@NotNull String rsqlParam, @NotNull Pageable pageReq, - Boolean deleted); - - /** - * method retrieves all {@link DistributionSet}s from the repository in the - * following order: - *

- * 1) {@link DistributionSet}s which have the given {@link Target} as - * {@link TargetStatus#getInstalledDistributionSet()} - *

- * 2) {@link DistributionSet}s which have the given {@link Target} as - * {@link Target#getAssignedDistributionSet()} - *

- * 3) {@link DistributionSet}s which have no connection to the given - * {@link Target} ordered by ID of the DistributionSet. - * - * @param pageable - * the page request to page the result set * - * @param distributionSetFilterBuilder - * has details of filters to be applied - * @param assignedOrInstalled - * the controllerID of the Target to be ordered by - * @return - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsAllOrderedByLinkTarget(@NotNull Pageable pageable, - @NotNull DistributionSetFilterBuilder distributionSetFilterBuilder, @NotEmpty String assignedOrInstalled); - - /** - * retrieves {@link DistributionSet}s by filtering on the given parameters. - * - * @param pageable - * page parameter - * @param distributionSetFilter - * has details of filters to be applied. - * @return the page of found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsByFilters(@NotNull Pageable pageable, - @NotNull DistributionSetFilter distributionSetFilter); - - /** - * @param id - * as {@link DistributionSetType#getId()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeById(@NotNull Long id); - - /** - * @param key - * as {@link DistributionSetType#getKey()} - * @return {@link DistributionSetType} if found or null if not - */ - - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeByKey(@NotNull String key); - - /** - * @param name - * as {@link DistributionSetType#getName()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeByName(@NotEmpty String name); - - /** - * @param pageable - * parameter - * @return all {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetTypesAll(@NotNull Pageable pageable); - - /** - * Generic predicate based query for {@link DistributionSetType}. - * - * @param rsqlParam - * rsql query string - * @param pageable - * parameter for paging - * - * @return the found {@link SoftwareModuleType}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * finds a single distribution set meta data by its id. - * - * @param id - * the id of the distribution set meta data containing the meta - * data key and the ID of the distribution set - * @return the found DistributionSetMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key); - - /** - * Checks if a {@link DistributionSet} is currently in use by a target in - * the repository. - * - * @param distributionSet - * to check - * - * @return true if in use - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - boolean isDistributionSetInUse(@NotNull DistributionSet distributionSet); - - /** - * {@link Entity} based method call for - * {@link #toggleTagAssignment(Collection, String)}. - * - * @param sets - * to toggle for - * @param tag - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection sets, - @NotNull DistributionSetTag tag); - - /** - * Toggles {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s by means that if some (or all) of the targets in - * the list have the {@link Tag} not yet assigned, they will be. If all of - * theme have the tag already assigned they will be removed instead. - * - * @param dsIds - * to toggle for - * @param tagName - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection dsIds, @NotNull String tagName); - - /** - * Unassign all {@link DistributionSet} from a given - * {@link DistributionSetTag} . - * - * @param tag - * to unassign all ds - * @return list of unassigned ds - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List unAssignAllDistributionSetsByTag(@NotNull DistributionSetTag tag); - - /** - * Unassigns a {@link SoftwareModule} form an existing - * {@link DistributionSet}. - * - * @param ds - * to get unassigned form - * @param softwareModule - * to get unassigned - * @return the updated {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet unassignSoftwareModule(@NotNull DistributionSet ds, @NotNull SoftwareModule softwareModule); - - /** - * Unassign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}. - * - * @param dsId - * to unassign for - * @param distributionSetTag - * to unassign - * @return the unassigned ds or if no ds is unassigned - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet unAssignTag(@NotNull Long dsId, @NotNull DistributionSetTag distributionSetTag); - - /** - * Updates existing {@link DistributionSet}. - * - * @param ds - * to update - * @return the saved {@link Entity}. - * @throws NullPointerException - * of {@link DistributionSet#getId()} is null - * @throw DataDependencyViolationException in case of illegal update - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet updateDistributionSet(@NotNull DistributionSet ds); - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetMetadata updateDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); - - /** - * Updates existing {@link DistributionSetType}. However, keep in mind that - * is not possible to change the {@link DistributionSetTypeElement}s while - * the DS type is already in use. - * - * @param dsType - * to update - * @return updated {@link Entity} - * - * @throws EntityReadOnlyException - * if use tries to change the {@link DistributionSetTypeElement} - * s while the DS type is already in use. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetType updateDistributionSetType(@NotNull DistributionSetType dsType); - -} +/** + * 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; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Tag; +import org.eclipse.hawkbit.repository.model.Target; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link DistributionSet}s. + * + */ +public interface DistributionSetManagement { + + // TODO rename/document the whole with details thing (document what the + // details are and maybe find a better name, e.g. with dependencies?) + + /** + * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. + * + * @param ds + * to assign and update + * @param softwareModules + * to get assigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet assignSoftwareModules(@NotNull DistributionSet ds, Set softwareModules); + + /** + * Assign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s. + * + * @param dsIds + * to assign for + * @param tag + * to assign + * @return list of assigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List assignTag(@NotEmpty Collection dsIds, @NotNull DistributionSetTag tag); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsAll(); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @param type + * to look for + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsByType(@NotNull DistributionSetType type); + + /** + * @return number of {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetTypesAll(); + + /** + * Creates a new {@link DistributionSet}. + * + * @param dSet + * {@link DistributionSet} to be created + * @return the new persisted {@link DistributionSet} + * + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSet createDistributionSet(@NotNull DistributionSet dSet); + + /** + * creates a list of distribution set meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created distribution set meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createDistributionSetMetadata(@NotEmpty Collection metadata); + + /** + * creates or updates a single distribution set meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created distribution set meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata createDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Creates multiple {@link DistributionSet}s. + * + * @param distributionSets + * to be created + * @return the new {@link DistributionSet}s + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSets(@NotNull Collection distributionSets); + + /** + * Creates new {@link DistributionSetType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSetType createDistributionSetType(@NotNull DistributionSetType type); + + /** + * Creates multiple {@link DistributionSetType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSetTypes(@NotNull Collection types); + + /** + *

+ * {@link DistributionSet} can be deleted/erased from the repository if they + * have never been assigned to any {@link UpdateAction} or {@link Target}. + *

+ * + *

+ * If they have been assigned that need to be marked as deleted which as a + * result means that they cannot be assigned anymore to any targets. (define + * e.g. findByDeletedFalse()) + *

+ * + * @param set + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotNull DistributionSet set); + + /** + * Deleted {@link DistributionSet}s by their IDs. That is either a soft + * delete of the entities have been linked to an {@link UpdateAction} before + * or a hard delete if not. + * + * @param distributionSetIDs + * to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotEmpty Long... distributionSetIDs); + + /** + * deletes a distribution set meta data entry. + * + * @param id + * the ID of the distribution set meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key); + + /** + * Deletes or mark as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSetType(@NotNull DistributionSetType type); + + /** + * retrieves the distribution set for a given action. + * + * @param action + * the action associated with the distribution set + * @return the distribution set which is associated with the action + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByAction(@NotNull Action action); + + /** + * Find {@link DistributionSet} based on given ID without details, e.g. + * {@link DistributionSet#getAgentHub()}. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetById(@NotNull Long distid); + + /** + * Find {@link DistributionSet} based on given ID including (lazy loaded) + * details, e.g. {@link DistributionSet#getAgentHub()}. + * + * Note: for performance reasons it is recommended to use + * {@link #findDistributionSetById(Long)} if details are not necessary. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByIdWithDetails(@NotNull Long distid); + + /** + * Find distribution set by name and version. + * + * @param distributionName + * name of {@link DistributionSet}; case insensitive + * @param version + * version of {@link DistributionSet} + * @return the page with the found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByNameAndVersion(@NotEmpty String distributionName, @NotEmpty String version); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @return list of distributionSetMetadata for a given distribution set Id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param rsqlParam + * rsql query string + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves {@link DistributionSet} List for overview purposes (no + * {@link SoftwareModule}s and {@link DistributionSetTag}s). + * + * Please use {@link #findDistributionSetListWithDetails(Iterable)} if + * details are required. + * + * @param dist + * List of {@link DistributionSet} IDs to be found + * @return the found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetsAll(Collection dist); + + // TODO discuss: use enum instead of the true,false,null switch ? + /** + * finds all {@link DistributionSet}s. + * + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @param complete + * to true for returning only completed distribution + * sets or false for only incomplete ones nor + * null to return both. + * @param complete + * set to if false incomplete DS should also be + * shown. + * + * + * @return all found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByDeletedAndOrCompleted(@NotNull Pageable pageReq, Boolean deleted, + Boolean complete); + + /** + * finds all {@link DistributionSet}s. + * + * @param rsqlParam + * rsql query string + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @return all found {@link DistributionSet}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAll(@NotNull String rsqlParam, @NotNull Pageable pageReq, + Boolean deleted); + + /** + * method retrieves all {@link DistributionSet}s from the repository in the + * following order: + *

+ * 1) {@link DistributionSet}s which have the given {@link Target} as + * {@link TargetStatus#getInstalledDistributionSet()} + *

+ * 2) {@link DistributionSet}s which have the given {@link Target} as + * {@link Target#getAssignedDistributionSet()} + *

+ * 3) {@link DistributionSet}s which have no connection to the given + * {@link Target} ordered by ID of the DistributionSet. + * + * @param pageable + * the page request to page the result set * + * @param distributionSetFilterBuilder + * has details of filters to be applied + * @param assignedOrInstalled + * the controllerID of the Target to be ordered by + * @return + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAllOrderedByLinkTarget(@NotNull Pageable pageable, + @NotNull DistributionSetFilterBuilder distributionSetFilterBuilder, @NotEmpty String assignedOrInstalled); + + /** + * retrieves {@link DistributionSet}s by filtering on the given parameters. + * + * @param pageable + * page parameter + * @param distributionSetFilter + * has details of filters to be applied. + * @return the page of found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByFilters(@NotNull Pageable pageable, + @NotNull DistributionSetFilter distributionSetFilter); + + /** + * @param id + * as {@link DistributionSetType#getId()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeById(@NotNull Long id); + + /** + * @param key + * as {@link DistributionSetType#getKey()} + * @return {@link DistributionSetType} if found or null if not + */ + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByKey(@NotNull String key); + + /** + * @param name + * as {@link DistributionSetType#getName()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByName(@NotEmpty String name); + + /** + * @param pageable + * parameter + * @return all {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull Pageable pageable); + + /** + * Generic predicate based query for {@link DistributionSetType}. + * + * @param rsqlParam + * rsql query string + * @param pageable + * parameter for paging + * + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * finds a single distribution set meta data by its id. + * + * @param id + * the id of the distribution set meta data containing the meta + * data key and the ID of the distribution set + * @return the found DistributionSetMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key); + + /** + * Checks if a {@link DistributionSet} is currently in use by a target in + * the repository. + * + * @param distributionSet + * to check + * + * @return true if in use + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + boolean isDistributionSetInUse(@NotNull DistributionSet distributionSet); + + /** + * {@link Entity} based method call for + * {@link #toggleTagAssignment(Collection, String)}. + * + * @param sets + * to toggle for + * @param tag + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection sets, + @NotNull DistributionSetTag tag); + + /** + * Toggles {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s by means that if some (or all) of the targets in + * the list have the {@link Tag} not yet assigned, they will be. If all of + * theme have the tag already assigned they will be removed instead. + * + * @param dsIds + * to toggle for + * @param tagName + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection dsIds, @NotNull String tagName); + + /** + * Unassign all {@link DistributionSet} from a given + * {@link DistributionSetTag} . + * + * @param tag + * to unassign all ds + * @return list of unassigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List unAssignAllDistributionSetsByTag(@NotNull DistributionSetTag tag); + + /** + * Unassigns a {@link SoftwareModule} form an existing + * {@link DistributionSet}. + * + * @param ds + * to get unassigned form + * @param softwareModule + * to get unassigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unassignSoftwareModule(@NotNull DistributionSet ds, @NotNull SoftwareModule softwareModule); + + /** + * Unassign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}. + * + * @param dsId + * to unassign for + * @param distributionSetTag + * to unassign + * @return the unassigned ds or if no ds is unassigned + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unAssignTag(@NotNull Long dsId, @NotNull DistributionSetTag distributionSetTag); + + /** + * Updates existing {@link DistributionSet}. + * + * @param ds + * to update + * @return the saved {@link Entity}. + * @throws NullPointerException + * of {@link DistributionSet#getId()} is null + * @throw DataDependencyViolationException in case of illegal update + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet updateDistributionSet(@NotNull DistributionSet ds); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata updateDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Updates existing {@link DistributionSetType}. However, keep in mind that + * is not possible to change the {@link DistributionSetTypeElement}s while + * the DS type is already in use. + * + * @param dsType + * to update + * @return updated {@link Entity} + * + * @throws EntityReadOnlyException + * if use tries to change the {@link DistributionSetTypeElement} + * s while the DS type is already in use. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetType updateDistributionSetType(@NotNull DistributionSetType dsType); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index 0934e871e..e48aaa3ab 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -1,486 +1,504 @@ -/** - * 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; - -import java.util.Collection; -import java.util.List; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; -import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.security.access.prepost.PreAuthorize; - -/** - * Service for managing {@link SoftwareModule}s. - * - */ -public interface SoftwareManagement { - - /** - * Counts {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param searchText - * to search for in name and version - * @param type - * to filter the result - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModuleByFilters(String searchText, SoftwareModuleType type); - - /** - * Count all {@link SoftwareModule}s in the repository that are not marked - * as deleted. - * - * @return number of {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModulesAll(); - - /** - * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. - * - * @param type - * to count - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModulesByType(@NotNull SoftwareModuleType type); - - /** - * @return number of {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModuleTypesAll(); - - /** - * Create {@link SoftwareModule}s in the repository. - * - * @param swModules - * {@link SoftwareModule}s to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createSoftwareModule(@NotNull Collection swModules); - - /** - * - * @param swModule - * SoftwareModule to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - SoftwareModule createSoftwareModule(@NotNull SoftwareModule swModule); - - /** - * creates a list of software module meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created software module meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List createSoftwareModuleMetadata(@NotNull Collection metadata); - - /** - * creates or updates a single software module meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created software module meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); - - /** - * Creates multiple {@link SoftwareModuleType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createSoftwareModuleType(@NotNull final Collection types); - - /** - * Creates new {@link SoftwareModuleType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - SoftwareModuleType createSoftwareModuleType(@NotNull SoftwareModuleType type); - - /** - * Deletes the given {@link SoftwareModule} {@link Entity}. - * - * @param bsm - * is the {@link SoftwareModule} to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModule(@NotNull SoftwareModule bsm); - - /** - * deletes a software module meta data entry. - * - * @param id - * the ID of the software module meta data to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key); - - /** - * Deletes {@link SoftwareModule}s which is any if the given ids. - * - * @param ids - * of the Software Modules to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModules(@NotNull Collection ids); - - /** - * Deletes or marks as delete in case the type is in use. - * - * @param type - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModuleType(@NotNull SoftwareModuleType type); - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleByAssignedTo(@NotNull Pageable pageable, @NotNull DistributionSet set); - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @param type - * to filter - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet} filtered by {@link SoftwareModuleType}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleByAssignedToAndType(@NotNull Pageable pageable, @NotNull DistributionSet set, - @NotNull SoftwareModuleType type); - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param pageable - * page parameter - * @param searchText - * to be filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * to be filtered as "like" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModuleByFilters(@NotNull Pageable pageable, String searchText, - SoftwareModuleType type); - - /** - * Finds {@link SoftwareModule} by given id. - * - * @param id - * to search for - * @return the found {@link SoftwareModule}s or null if not - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - SoftwareModule findSoftwareModuleById(@NotNull Long id); - - /** - * retrieves {@link SoftwareModule} by their name AND version AND type.. - * - * @param name - * of the {@link SoftwareModule} - * @param version - * of the {@link SoftwareModule} - * @param type - * of the {@link SoftwareModule} - * @return the found {@link SoftwareModule} or null - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty String name, @NotEmpty String version, - @NotNull SoftwareModuleType type); - - /** - * finds a single software module meta data by its id. - * - * @param id - * the id of the software module meta data containing the meta - * data key and the ID of the software module - * @return the found SoftwareModuleMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key); - - /** - * finds all meta data by the given software module id. - * - * @param swId - * the software module id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long swId, - @NotNull Pageable pageable); - - /** - * finds all meta data by the given software module id. - * - * @param softwareModuleId - * the software module id to retrieve the meta data from - * @param spec - * the specification to filter the result - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long softwareModuleId, - @NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * search text and {@link SoftwareModule#getType()} that are not marked as - * deleted and sort them by means of given distribution set related modules - * on top of the list. - * - * After that the modules are sorted by {@link SoftwareModule#getName()} and - * {@link SoftwareModule#getVersion()} in ascending order. - * - * @param pageable - * page parameter - * @param orderByDistributionId - * the ID of distribution set to be ordered on top - * @param searchText - * filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * filtered as "equal" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( - @NotNull Pageable pageable, @NotNull Long orderByDistributionId, String searchText, - SoftwareModuleType type); - - /** - * Retrieves all software modules. Deleted ones are filtered. - * - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModulesAll(@NotNull Pageable pageable); - - /** - * Retrieves all software modules with a given list of ids - * {@link SoftwareModule#getId()}. - * - * @param ids - * to search for - * @return {@link List} of found {@link SoftwareModule}s - */ - List findSoftwareModulesById(@NotEmpty Collection ids); - - /** - * Retrieves all {@link SoftwareModule}s with a given specification. - * - * @param spec - * the specification to filter the software modules - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModulesByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} - * . - * - * @param pageable - * page parameters - * @param type - * to be filtered on - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModulesByType(@NotNull Pageable pageable, @NotNull SoftwareModuleType type); - - /** - * - * @param id - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getId()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeById(@NotNull Long id); - - /** - * - * @param key - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getKey()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key); - - /** - * - * @param name - * to search for - * @return all {@link SoftwareModuleType}s in the repository with given - * {@link SoftwareModuleType#getName()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeByName(@NotNull String name); - - /** - * @param pageable - * parameter - * @return all {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleTypesAll(@NotNull Pageable pageable); - - /** - * Retrieves all {@link SoftwareModuleType}s with a given specification. - * - * @param spec - * the specification to filter the software modules types - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModuleType}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Retrieves software module including details ( - * {@link SoftwareModule#getArtifacts()}). - * - * @param id - * parameter - * @param isDeleted - * parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); - - /** - * Updates existing {@link SoftwareModule}. Update-able values are - * {@link SoftwareModule#getDescription()} - * {@link SoftwareModule#getVendor()}. - * - * @param sm - * to update - * - * @return the saved {@link Entity}. - * - * @throws NullPointerException - * of {@link SoftwareModule#getId()} is null - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModule updateSoftwareModule(@NotNull SoftwareModule sm); - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); - - /** - * Updates existing {@link SoftwareModuleType}. Update-able value is - * {@link SoftwareModuleType#getDescription()} and - * {@link SoftwareModuleType#getColour()}. - * - * @param sm - * to update - * @return updated {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); - -} +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Service for managing {@link SoftwareModule}s. + * + */ +public interface SoftwareManagement { + + /** + * Counts {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param searchText + * to search for in name and version + * @param type + * to filter the result + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleByFilters(String searchText, SoftwareModuleType type); + + /** + * Count all {@link SoftwareModule}s in the repository that are not marked + * as deleted. + * + * @return number of {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesAll(); + + /** + * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. + * + * @param type + * to count + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesByType(@NotNull SoftwareModuleType type); + + /** + * @return number of {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleTypesAll(); + + /** + * Create {@link SoftwareModule}s in the repository. + * + * @param swModules + * {@link SoftwareModule}s to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModule(@NotNull Collection swModules); + + /** + * + * @param swModule + * SoftwareModule to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModule createSoftwareModule(@NotNull SoftwareModule swModule); + + /** + * creates a list of software module meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created software module meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createSoftwareModuleMetadata(@NotNull Collection metadata); + + /** + * creates or updates a single software module meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created software module meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Creates multiple {@link SoftwareModuleType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModuleType(@NotNull final Collection types); + + /** + * Creates new {@link SoftwareModuleType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModuleType createSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * Deletes the given {@link SoftwareModule} {@link Entity}. + * + * @param bsm + * is the {@link SoftwareModule} to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModule(@NotNull SoftwareModule bsm); + + /** + * deletes a software module meta data entry. + * + * @param id + * the ID of the software module meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key); + + /** + * Deletes {@link SoftwareModule}s which is any if the given ids. + * + * @param ids + * of the Software Modules to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModules(@NotNull Collection ids); + + /** + * Deletes or marks as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedTo(@NotNull Pageable pageable, @NotNull DistributionSet set); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @param type + * to filter + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet} filtered by {@link SoftwareModuleType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedToAndType(@NotNull Pageable pageable, @NotNull DistributionSet set, + @NotNull SoftwareModuleType type); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param pageable + * page parameter + * @param searchText + * to be filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * to be filtered as "like" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleByFilters(@NotNull Pageable pageable, String searchText, + SoftwareModuleType type); + + /** + * Finds {@link SoftwareModule} by given id. + * + * @param id + * to search for + * @return the found {@link SoftwareModule}s or null if not + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + SoftwareModule findSoftwareModuleById(@NotNull Long id); + + /** + * retrieves {@link SoftwareModule} by their name AND version AND type.. + * + * @param name + * of the {@link SoftwareModule} + * @param version + * of the {@link SoftwareModule} + * @param type + * of the {@link SoftwareModule} + * @return the found {@link SoftwareModule} or null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty String name, @NotEmpty String version, + @NotNull SoftwareModuleType type); + + /** + * finds a single software module meta data by its id. + * + * @param id + * the id of the software module meta data containing the meta + * data key and the ID of the software module + * @return the found SoftwareModuleMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key); + + /** + * finds all meta data by the given software module id. + * + * @param swId + * the software module id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long swId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + * @param spec + * the specification to filter the result + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long softwareModuleId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * search text and {@link SoftwareModule#getType()} that are not marked as + * deleted and sort them by means of given distribution set related modules + * on top of the list. + * + * After that the modules are sorted by {@link SoftwareModule#getName()} and + * {@link SoftwareModule#getVersion()} in ascending order. + * + * @param pageable + * page parameter + * @param orderByDistributionId + * the ID of distribution set to be ordered on top + * @param searchText + * filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * filtered as "equal" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + @NotNull Pageable pageable, @NotNull Long orderByDistributionId, String searchText, + SoftwareModuleType type); + + /** + * Retrieves all software modules. Deleted ones are filtered. + * + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesAll(@NotNull Pageable pageable); + + /** + * Retrieves all software modules with a given list of ids + * {@link SoftwareModule#getId()}. + * + * @param ids + * to search for + * @return {@link List} of found {@link SoftwareModule}s + */ + List findSoftwareModulesById(@NotEmpty Collection ids); + + /** + * Retrieves all {@link SoftwareModule}s with a given specification. + * + * @param spec + * the specification to filter the software modules + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModulesByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} + * . + * + * @param pageable + * page parameters + * @param type + * to be filtered on + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesByType(@NotNull Pageable pageable, @NotNull SoftwareModuleType type); + + /** + * + * @param id + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getId()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeById(@NotNull Long id); + + /** + * + * @param key + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getKey()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key); + + /** + * + * @param name + * to search for + * @return all {@link SoftwareModuleType}s in the repository with given + * {@link SoftwareModuleType#getName()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByName(@NotNull String name); + + /** + * @param pageable + * parameter + * @return all {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull Pageable pageable); + + /** + * Retrieves all {@link SoftwareModuleType}s with a given specification. + * + * @param spec + * the specification to filter the software modules types + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves software module including details ( + * {@link SoftwareModule#getArtifacts()}). + * + * @param id + * parameter + * @param isDeleted + * parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); + + /** + * Updates existing {@link SoftwareModule}. Update-able values are + * {@link SoftwareModule#getDescription()} + * {@link SoftwareModule#getVendor()}. + * + * @param sm + * to update + * + * @return the saved {@link Entity}. + * + * @throws NullPointerException + * of {@link SoftwareModule#getId()} is null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModule updateSoftwareModule(@NotNull SoftwareModule sm); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Updates existing {@link SoftwareModuleType}. Update-able value is + * {@link SoftwareModuleType#getDescription()} and + * {@link SoftwareModuleType#getColour()}. + * + * @param sm + * to update + * @return updated {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); + + /** + * finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + * @return result of all meta data entries for a given software + * module id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId); + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index b94677fb9..306b9bd80 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -173,39 +173,36 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override @Modifying @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteDistributionSet(final Long... distributionSetIDs) { - final List toHardDelete = new ArrayList<>(); + public void deleteDistributionSet(final Long... distributionSetIDs) { + final List toHardDelete = new ArrayList<>(); - final List assigned = distributionSetRepository - .findAssignedToTargetDistributionSetsById(distributionSetIDs); - assigned.addAll(distributionSetRepository - .findAssignedToRolloutDistributionSetsById(distributionSetIDs)); + final List assigned = distributionSetRepository + .findAssignedToTargetDistributionSetsById(distributionSetIDs); + assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs)); - // soft delete assigned - if (!assigned.isEmpty()) { - distributionSetRepository.deleteDistributionSet(assigned - .toArray(new Long[assigned.size()])); - } + // soft delete assigned + if (!assigned.isEmpty()) { + distributionSetRepository.deleteDistributionSet(assigned.toArray(new Long[assigned.size()])); + } - // mark the rest as hard delete - for (final Long setId : distributionSetIDs) { - if (!assigned.contains(setId)) { - toHardDelete.add(setId); - } - } + // mark the rest as hard delete + for (final Long setId : distributionSetIDs) { + if (!assigned.contains(setId)) { + toHardDelete.add(setId); + } + } - // hard delete the rest if exixts - if (!toHardDelete.isEmpty()) { - // don't give the delete statement an empty list, JPA/Oracle cannot - // handle the empty list - distributionSetRepository.deleteByIdIn(toHardDelete); - } + // hard delete the rest if exixts + if (!toHardDelete.isEmpty()) { + // don't give the delete statement an empty list, JPA/Oracle cannot + // handle the empty list + distributionSetRepository.deleteByIdIn(toHardDelete); + } - afterCommit.afterCommit(() -> eventBus - .post(new DistributionDeletedEvent(tenantAware - .getCurrentTenant(), distributionSetIDs))); + afterCommit.afterCommit( + () -> eventBus.post(new DistributionDeletedEvent(tenantAware.getCurrentTenant(), distributionSetIDs))); - } + } @Override @Modifying @@ -530,6 +527,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) { + entityManager.merge((JpaDistributionSet) distributionSet).setLastModifiedAt(0L); distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key)); } @@ -544,6 +542,15 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { pageable); } + @Override + public List findDistributionSetMetadataByDistributionSetId(final Long distributionSetId) { + + return new ArrayList(distributionSetMetadataRepository + .findAll((Specification) (root, query, cb) -> cb.equal( + root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), + distributionSetId))); + } + @Override public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final String rsqlParam, final Pageable pageable) { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index b561667a9..afe1a1e02 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -1,663 +1,672 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.jpa; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.ListJoin; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.ArtifactManagement; -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.SoftwareModuleFields; -import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; -import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; -import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; -import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; -import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; -import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import com.google.common.base.Strings; -import com.google.common.collect.Sets; - -/** - * JPA implementation of {@link SoftwareManagement}. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -public class JpaSoftwareManagement implements SoftwareManagement { - - @Autowired - private EntityManager entityManager; - - @Autowired - private DistributionSetRepository distributionSetRepository; - - @Autowired - private DistributionSetTypeRepository distributionSetTypeRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - - @Autowired - private SoftwareModuleTypeRepository softwareModuleTypeRepository; - - @Autowired - private NoCountPagingRepository criteriaNoCountDao; - - @Autowired - private AuditorAware auditorProvider; - - @Autowired - private ArtifactManagement artifactManagement; - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModule updateSoftwareModule(final SoftwareModule sm) { - checkNotNull(sm.getId()); - - final JpaSoftwareModule module = softwareModuleRepository.findOne(sm.getId()); - - boolean updated = false; - if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { - module.setDescription(sm.getDescription()); - updated = true; - } - if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { - module.setVendor(sm.getVendor()); - updated = true; - } - - return updated ? softwareModuleRepository.save(module) : module; - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModuleType updateSoftwareModuleType(final SoftwareModuleType sm) { - checkNotNull(sm.getId()); - - final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); - - boolean updated = false; - if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) { - type.setDescription(sm.getDescription()); - updated = true; - } - if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { - type.setColour(sm.getColour()); - updated = true; - } - return updated ? softwareModuleTypeRepository.save(type) : type; - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModule createSoftwareModule(final SoftwareModule swModule) { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - return softwareModuleRepository.save((JpaSoftwareModule) swModule); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public List createSoftwareModule(final Collection swModules) { - swModules.forEach(swModule -> { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - }); - - @SuppressWarnings({ "unchecked", "rawtypes" }) - final Collection jpaCast = (Collection) swModules; - - return new ArrayList<>(softwareModuleRepository.save(jpaCast)); - } - - @Override - public Slice findSoftwareModulesByType(final Pageable pageable, final SoftwareModuleType type) { - - final List> specList = new LinkedList<>(); - - Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - private static Slice convertSmPage(final Slice findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); - } - - private static Page convertSmPage(final Page findAll, final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - private static Page convertSmMdPage(final Page findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - @Override - public Long countSoftwareModulesByType(final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public SoftwareModule findSoftwareModuleById(final Long id) { - return artifactManagement.findSoftwareModuleById(id); - } - - @Override - public SoftwareModule findSoftwareModuleByNameAndVersion(final String name, final String version, - final SoftwareModuleType type) { - - return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, (JpaSoftwareModuleType) type); - } - - private boolean isUnassigned(final JpaSoftwareModule bsmMerged) { - return distributionSetRepository.findByModules(bsmMerged).isEmpty(); - } - - private Slice findSwModuleByCriteriaAPI(final Pageable pageable, - final List> specList) { - return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, - JpaSoftwareModule.class); - } - - private Long countSwModuleByCriteriaAPI(final List> specList) { - return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); - } - - private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) { - for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { - artifactManagement.deleteLocalArtifact(localArtifact); - } - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModules(final Collection ids) { - final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); - final Set assignedModuleIds = new HashSet<>(); - swModulesToDelete.forEach(swModule -> { - - // delete binary data of artifacts - deleteGridFsArtifacts(swModule); - - if (isUnassigned(swModule)) { - - softwareModuleRepository.delete(swModule); - - } else { - - assignedModuleIds.add(swModule.getId()); - } - }); - - if (!assignedModuleIds.isEmpty()) { - String currentUser = null; - if (auditorProvider != null) { - currentUser = auditorProvider.getCurrentAuditor(); - } - softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, - assignedModuleIds.toArray(new Long[0])); - } - } - - @Override - public Slice findSoftwareModulesAll(final Pageable pageable) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(JpaSoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - @Override - public Long countSoftwareModulesAll() { - - final List> specList = new ArrayList<>(); - - final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public SoftwareModule findSoftwareModuleWithDetails(final Long id) { - return artifactManagement.findSoftwareModuleWithDetails(id); - } - - @Override - public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); - - return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); - } - - @Override - public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { - - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); - - return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); - } - - private static Page convertSmTPage(final Page findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - @Override - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public List findSoftwareModulesById(final Collection ids) { - return new ArrayList<>(softwareModuleRepository.findByIdIn(ids)); - } - - @Override - public Slice findSoftwareModuleByFilters(final Pageable pageable, final String searchText, - final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - } - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(JpaSoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - @Override - public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( - final Pageable pageable, final Long orderByDistributionId, final String searchText, - final SoftwareModuleType ty) { - final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; - - final List resultList = new ArrayList<>(); - final int pageSize = pageable.getPageSize(); - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - - // get the assigned software modules - final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); - final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); - assignedQuery.distinct(true); - final ListJoin assignedDsJoin = assignedRoot - .join(JpaSoftwareModule_.assignedTo); - // build the specifications and then to predicates necessary by the - // given filters - final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), - assignedRoot, assignedQuery, cb, - cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId)); - // if we have some predicates then add it to the where clause of the - // multi select - assignedQuery.where(specPredicate); - assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)), - cb.asc(assignedRoot.get(JpaSoftwareModule_.version))); - // don't page the assigned query on database, we need all assigned - // software modules to filter - // them out in the unassigned query - final List assignedSoftwareModules = entityManager.createQuery(assignedQuery) - .getResultList(); - // map result - if (pageable.getOffset() < assignedSoftwareModules.size()) { - assignedSoftwareModules - .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) - .forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true))); - } - - if (assignedSoftwareModules.size() >= pageSize) { - return new SliceImpl<>(resultList); - } - - // get the unassigned software modules - final CriteriaQuery unassignedQuery = cb.createQuery(JpaSoftwareModule.class); - unassignedQuery.distinct(true); - final Root unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class); - - Predicate[] unassignedSpec; - if (!assignedSoftwareModules.isEmpty()) { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id) - .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); - } else { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb); - } - - unassignedQuery.where(unassignedSpec); - unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)), - cb.asc(unassignedRoot.get(JpaSoftwareModule_.version))); - final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) - .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) - .setMaxResults(pageSize).getResultList(); - // map result - unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false))); - - return new SliceImpl<>(resultList); - } - - private static List> buildSpecificationList(final String searchText, - final JpaSoftwareModuleType type) { - final List> specList = new ArrayList<>(); - if (!Strings.isNullOrEmpty(searchText)) { - specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); - } - if (type != null) { - specList.add(SoftwareModuleSpecification.equalType(type)); - } - specList.add(SoftwareModuleSpecification.isDeletedFalse()); - return specList; - } - - private Predicate[] specificationsToPredicate(final List> specifications, - final Root root, final CriteriaQuery query, final CriteriaBuilder cb, - final Predicate... additionalPredicates) { - final List predicates = new ArrayList<>(); - specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); - for (final Predicate predicate : additionalPredicates) { - predicates.add(predicate); - } - return predicates.toArray(new Predicate[predicates.size()]); - } - - @Override - public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - } - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public Page findSoftwareModuleTypesAll(final Pageable pageable) { - return softwareModuleTypeRepository.findByDeleted(pageable, false); - } - - @Override - public Long countSoftwareModuleTypesAll() { - return softwareModuleTypeRepository.countByDeleted(false); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeByKey(final String key) { - return softwareModuleTypeRepository.findByKey(key); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeById(final Long id) { - return softwareModuleTypeRepository.findOne(id); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeByName(final String name) { - return softwareModuleTypeRepository.findByName(name); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModuleType createSoftwareModuleType(final SoftwareModuleType type) { - if (type.getId() != null) { - throw new EntityAlreadyExistsException("Given type contains an Id!"); - } - - return softwareModuleTypeRepository.save((JpaSoftwareModuleType) type); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModuleType(final SoftwareModuleType ty) { - final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; - - if (softwareModuleRepository.countByType(type) > 0 - || distributionSetTypeRepository.countByElementsSmType(type) > 0) { - final JpaSoftwareModuleType toDelete = entityManager.merge(type); - toDelete.setDeleted(true); - softwareModuleTypeRepository.save(toDelete); - } else { - softwareModuleTypeRepository.delete(type.getId()); - } - } - - @Override - public Page findSoftwareModuleByAssignedTo(final Pageable pageable, final DistributionSet set) { - return softwareModuleRepository.findByAssignedTo(pageable, (JpaDistributionSet) set); - } - - @Override - public Page findSoftwareModuleByAssignedToAndType(final Pageable pageable, - final DistributionSet set, final SoftwareModuleType type) { - return softwareModuleRepository.findByAssignedToAndType(pageable, (JpaDistributionSet) set, - (JpaSoftwareModuleType) type); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public SoftwareModuleMetadata createSoftwareModuleMetadata(final SoftwareModuleMetadata md) { - final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; - - if (softwareModuleMetadataRepository.exists(metadata.getId())) { - throwMetadataKeyAlreadyExists(metadata.getId().getKey()); - } - // merge base software module so optLockRevision gets updated and audit - // log written because - // modifying metadata is modifying the base software module itself for - // auditing purposes. - entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public List createSoftwareModuleMetadata(final Collection md) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - final Collection metadata = (Collection) md; - - for (final JpaSoftwareModuleMetadata softwareModuleMetadata : metadata) { - checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); - } - metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L)); - return new ArrayList<>(softwareModuleMetadataRepository.save(metadata)); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public SoftwareModuleMetadata updateSoftwareModuleMetadata(final SoftwareModuleMetadata md) { - final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; - - // check if exists otherwise throw entity not found exception - findSoftwareModuleMetadata(metadata.getId()); - // touch it to update the lock revision because we are modifying the - // software module - // indirectly - entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public void deleteSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { - softwareModuleMetadataRepository.delete(new SwMetadataCompositeKey(softwareModule, key)); - } - - @Override - public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long swId, - final Pageable pageable) { - return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); - } - - @Override - public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, - final String rsqlParam, final Pageable pageable) { - - final Specification spec = RSQLUtility.parse(rsqlParam, - SoftwareModuleMetadataFields.class); - return convertSmMdPage( - softwareModuleMetadataRepository - .findAll( - (Specification) (root, query, cb) -> cb.and( - cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) - .get(JpaSoftwareModule_.id), softwareModuleId), - spec.toPredicate(root, query, cb)), - pageable), - pageable); - } - - @Override - public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { - return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); - } - - private SoftwareModuleMetadata findSoftwareModuleMetadata(final SwMetadataCompositeKey id) { - final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); - if (findOne == null) { - throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); - } - return findOne; - } - - private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { - if (softwareModuleMetadataRepository.exists(metadataId)) { - throw new EntityAlreadyExistsException( - "Metadata entry with key '" + metadataId.getKey() + "' already exists"); - } - } - - private static void throwMetadataKeyAlreadyExists(final String metadataKey) { - throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModule(final SoftwareModule bsm) { - deleteSoftwareModules(Sets.newHashSet(bsm.getId())); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public List createSoftwareModuleType(final Collection types) { - - return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); - } - -} +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.SoftwareModuleFields; +import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; +import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; +import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; + +/** + * JPA implementation of {@link SoftwareManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaSoftwareManagement implements SoftwareManagement { + + @Autowired + private EntityManager entityManager; + + @Autowired + private DistributionSetRepository distributionSetRepository; + + @Autowired + private DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + + @Autowired + private SoftwareModuleTypeRepository softwareModuleTypeRepository; + + @Autowired + private NoCountPagingRepository criteriaNoCountDao; + + @Autowired + private AuditorAware auditorProvider; + + @Autowired + private ArtifactManagement artifactManagement; + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule updateSoftwareModule(final SoftwareModule sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModule module = softwareModuleRepository.findOne(sm.getId()); + + boolean updated = false; + if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { + module.setDescription(sm.getDescription()); + updated = true; + } + if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { + module.setVendor(sm.getVendor()); + updated = true; + } + + return updated ? softwareModuleRepository.save(module) : module; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType updateSoftwareModuleType(final SoftwareModuleType sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); + + boolean updated = false; + if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) { + type.setDescription(sm.getDescription()); + updated = true; + } + if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { + type.setColour(sm.getColour()); + updated = true; + } + return updated ? softwareModuleTypeRepository.save(type) : type; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule createSoftwareModule(final SoftwareModule swModule) { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + return softwareModuleRepository.save((JpaSoftwareModule) swModule); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModule(final Collection swModules) { + swModules.forEach(swModule -> { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + }); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection jpaCast = (Collection) swModules; + + return new ArrayList<>(softwareModuleRepository.save(jpaCast)); + } + + @Override + public Slice findSoftwareModulesByType(final Pageable pageable, final SoftwareModuleType type) { + + final List> specList = new LinkedList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + private static Slice convertSmPage(final Slice findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); + } + + private static Page convertSmPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Page convertSmMdPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Long countSoftwareModulesByType(final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleById(final Long id) { + return artifactManagement.findSoftwareModuleById(id); + } + + @Override + public SoftwareModule findSoftwareModuleByNameAndVersion(final String name, final String version, + final SoftwareModuleType type) { + + return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, (JpaSoftwareModuleType) type); + } + + private boolean isUnassigned(final JpaSoftwareModule bsmMerged) { + return distributionSetRepository.findByModules(bsmMerged).isEmpty(); + } + + private Slice findSwModuleByCriteriaAPI(final Pageable pageable, + final List> specList) { + return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, + JpaSoftwareModule.class); + } + + private Long countSwModuleByCriteriaAPI(final List> specList) { + return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); + } + + private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) { + for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { + artifactManagement.deleteLocalArtifact(localArtifact); + } + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModules(final Collection ids) { + final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); + final Set assignedModuleIds = new HashSet<>(); + swModulesToDelete.forEach(swModule -> { + + // delete binary data of artifacts + deleteGridFsArtifacts(swModule); + + if (isUnassigned(swModule)) { + + softwareModuleRepository.delete(swModule); + + } else { + + assignedModuleIds.add(swModule.getId()); + } + }); + + if (!assignedModuleIds.isEmpty()) { + String currentUser = null; + if (auditorProvider != null) { + currentUser = auditorProvider.getCurrentAuditor(); + } + softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, + assignedModuleIds.toArray(new Long[0])); + } + } + + @Override + public Slice findSoftwareModulesAll(final Pageable pageable) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Long countSoftwareModulesAll() { + + final List> specList = new ArrayList<>(); + + final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleWithDetails(final Long id) { + return artifactManagement.findSoftwareModuleWithDetails(id); + } + + @Override + public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); + + return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); + } + + @Override + public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); + + return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); + } + + private static Page convertSmTPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + public List findSoftwareModulesById(final Collection ids) { + return new ArrayList<>(softwareModuleRepository.findByIdIn(ids)); + } + + @Override + public Slice findSoftwareModuleByFilters(final Pageable pageable, final String searchText, + final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + final Pageable pageable, final Long orderByDistributionId, final String searchText, + final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + final List resultList = new ArrayList<>(); + final int pageSize = pageable.getPageSize(); + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + + // get the assigned software modules + final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); + final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); + assignedQuery.distinct(true); + final ListJoin assignedDsJoin = assignedRoot + .join(JpaSoftwareModule_.assignedTo); + // build the specifications and then to predicates necessary by the + // given filters + final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), + assignedRoot, assignedQuery, cb, + cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId)); + // if we have some predicates then add it to the where clause of the + // multi select + assignedQuery.where(specPredicate); + assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(assignedRoot.get(JpaSoftwareModule_.version))); + // don't page the assigned query on database, we need all assigned + // software modules to filter + // them out in the unassigned query + final List assignedSoftwareModules = entityManager.createQuery(assignedQuery) + .getResultList(); + // map result + if (pageable.getOffset() < assignedSoftwareModules.size()) { + assignedSoftwareModules + .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) + .forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true))); + } + + if (assignedSoftwareModules.size() >= pageSize) { + return new SliceImpl<>(resultList); + } + + // get the unassigned software modules + final CriteriaQuery unassignedQuery = cb.createQuery(JpaSoftwareModule.class); + unassignedQuery.distinct(true); + final Root unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class); + + Predicate[] unassignedSpec; + if (!assignedSoftwareModules.isEmpty()) { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id) + .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); + } else { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb); + } + + unassignedQuery.where(unassignedSpec); + unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(unassignedRoot.get(JpaSoftwareModule_.version))); + final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) + .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) + .setMaxResults(pageSize).getResultList(); + // map result + unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false))); + + return new SliceImpl<>(resultList); + } + + private static List> buildSpecificationList(final String searchText, + final JpaSoftwareModuleType type) { + final List> specList = new ArrayList<>(); + if (!Strings.isNullOrEmpty(searchText)) { + specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); + } + if (type != null) { + specList.add(SoftwareModuleSpecification.equalType(type)); + } + specList.add(SoftwareModuleSpecification.isDeletedFalse()); + return specList; + } + + private Predicate[] specificationsToPredicate(final List> specifications, + final Root root, final CriteriaQuery query, final CriteriaBuilder cb, + final Predicate... additionalPredicates) { + final List predicates = new ArrayList<>(); + specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); + for (final Predicate predicate : additionalPredicates) { + predicates.add(predicate); + } + return predicates.toArray(new Predicate[predicates.size()]); + } + + @Override + public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public Page findSoftwareModuleTypesAll(final Pageable pageable) { + return softwareModuleTypeRepository.findByDeleted(pageable, false); + } + + @Override + public Long countSoftwareModuleTypesAll() { + return softwareModuleTypeRepository.countByDeleted(false); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByKey(final String key) { + return softwareModuleTypeRepository.findByKey(key); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeById(final Long id) { + return softwareModuleTypeRepository.findOne(id); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByName(final String name) { + return softwareModuleTypeRepository.findByName(name); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType createSoftwareModuleType(final SoftwareModuleType type) { + if (type.getId() != null) { + throw new EntityAlreadyExistsException("Given type contains an Id!"); + } + + return softwareModuleTypeRepository.save((JpaSoftwareModuleType) type); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModuleType(final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + if (softwareModuleRepository.countByType(type) > 0 + || distributionSetTypeRepository.countByElementsSmType(type) > 0) { + final JpaSoftwareModuleType toDelete = entityManager.merge(type); + toDelete.setDeleted(true); + softwareModuleTypeRepository.save(toDelete); + } else { + softwareModuleTypeRepository.delete(type.getId()); + } + } + + @Override + public Page findSoftwareModuleByAssignedTo(final Pageable pageable, final DistributionSet set) { + return softwareModuleRepository.findByAssignedTo(pageable, (JpaDistributionSet) set); + } + + @Override + public Page findSoftwareModuleByAssignedToAndType(final Pageable pageable, + final DistributionSet set, final SoftwareModuleType type) { + return softwareModuleRepository.findByAssignedToAndType(pageable, (JpaDistributionSet) set, + (JpaSoftwareModuleType) type); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata createSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + if (softwareModuleMetadataRepository.exists(metadata.getId())) { + throwMetadataKeyAlreadyExists(metadata.getId().getKey()); + } + // merge base software module so optLockRevision gets updated and audit + // log written because + // modifying metadata is modifying the base software module itself for + // auditing purposes. + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public List createSoftwareModuleMetadata(final Collection md) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection metadata = (Collection) md; + + for (final JpaSoftwareModuleMetadata softwareModuleMetadata : metadata) { + checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); + } + metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L)); + return new ArrayList<>(softwareModuleMetadataRepository.save(metadata)); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata updateSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + // check if exists otherwise throw entity not found exception + findSoftwareModuleMetadata(metadata.getId()); + // touch it to update the lock revision because we are modifying the + // software module + // indirectly + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public void deleteSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + softwareModuleMetadataRepository.delete(new SwMetadataCompositeKey(softwareModule, key)); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long swId, + final Pageable pageable) { + return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, + final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, + SoftwareModuleMetadataFields.class); + return convertSmMdPage( + softwareModuleMetadataRepository + .findAll( + (Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) + .get(JpaSoftwareModule_.id), softwareModuleId), + spec.toPredicate(root, query, cb)), + pageable), + pageable); + } + + @Override + public List findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) { + return new ArrayList<> ( softwareModuleMetadataRepository + .findAll( + (Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) + .get(JpaSoftwareModule_.id), softwareModuleId)))); + } + + @Override + public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); + } + + private SoftwareModuleMetadata findSoftwareModuleMetadata(final SwMetadataCompositeKey id) { + final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); + if (findOne == null) { + throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); + } + return findOne; + } + + private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { + if (softwareModuleMetadataRepository.exists(metadataId)) { + throw new EntityAlreadyExistsException( + "Metadata entry with key '" + metadataId.getKey() + "' already exists"); + } + } + + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { + throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModule(final SoftwareModule bsm) { + deleteSoftwareModules(Sets.newHashSet(bsm.getId())); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModuleType(final Collection types) { + + return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java index b6475f647..b96b59f6a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java @@ -222,7 +222,6 @@ public abstract class AbstractTableDetailsLayout extends populateLog(); populateDescription(); populateDetailsWidget(); - populateMetadataDetails(); } protected void populateLog() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java index d3892a9dc..cf41bdd4f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java @@ -40,38 +40,36 @@ import com.vaadin.ui.themes.ValoTheme; @SpringComponent @VaadinSessionScope -public class DistributionSetMetadatadetailslayout extends Table{ - +public class DistributionSetMetadatadetailslayout extends Table { + private static final long serialVersionUID = 2913758299611837718L; - - - private DistributionSetManagement distributionSetManagement; - + + private DistributionSetManagement distributionSetManagement; + private DsMetadataPopupLayout dsMetadataPopupLayout; private static final String METADATA_KEY = "Key"; - - private static final String VIEW ="view"; + + private static final String VIEW = "view"; private SpPermissionChecker permissionChecker; - + private transient EntityFactory entityFactory; private I18N i18n; - - private Long selectedDistSetId; - - /** - * - * @param i18n - * @param permissionChecker - * @param distributionSetManagement - * @param dsMetadataPopupLayout - */ + + private Long selectedDistSetId; + + /** + * + * @param i18n + * @param permissionChecker + * @param distributionSetManagement + * @param dsMetadataPopupLayout + */ public void init(final I18N i18n, final SpPermissionChecker permissionChecker, - final DistributionSetManagement distributionSetManagement, - final DsMetadataPopupLayout dsMetadataPopupLayout, - final EntityFactory entityFactory) { + final DistributionSetManagement distributionSetManagement, + final DsMetadataPopupLayout dsMetadataPopupLayout, final EntityFactory entityFactory) { this.i18n = i18n; this.permissionChecker = permissionChecker; this.distributionSetManagement = distributionSetManagement; @@ -80,7 +78,6 @@ public class DistributionSetMetadatadetailslayout extends Table{ createDSMetadataTable(); addCustomGeneratedColumns(); } - /** * Populate software module metadata. @@ -90,35 +87,15 @@ public class DistributionSetMetadatadetailslayout extends Table{ public void populateDSMetadata(final DistributionSet distributionSet) { removeAllItems(); if (null == distributionSet) { - return; + return; } selectedDistSetId = distributionSet.getId(); - final List dsMetadataList = distributionSet.getMetadata(); + final List dsMetadataList = distributionSetManagement + .findDistributionSetMetadataByDistributionSetId(selectedDistSetId); if (null != dsMetadataList && !dsMetadataList.isEmpty()) { dsMetadataList.forEach(dsMetadata -> setDSMetadataProperties(dsMetadata)); } - - } - - /** - * Create metadata . - * - * @param metadataKeyName - */ - public void createMetadata(final String metadataKeyName){ - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - final Item item = metadataContainer.addItem(metadataKeyName); - item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); - } - - /** - * Delete metadata. - * - * @param metadataKeyName - */ - public void deleteMetadata(final String metadataKeyName){ - final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); - metadataContainer.removeItem(metadataKeyName); + } private void createDSMetadataTable() { @@ -131,9 +108,9 @@ public class DistributionSetMetadatadetailslayout extends Table{ setContainerDataSource(getDistSetContainer()); setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); addDSMetadataTableHeader(); - setSizeFull(); - //same as height of other tabs in details tabsheet - setHeight(116,Unit.PIXELS); + setSizeFull(); + // same as height of other tabs in details tabsheet + setHeight(116, Unit.PIXELS); } private IndexedContainer getDistSetContainer() { @@ -141,7 +118,7 @@ public class DistributionSetMetadatadetailslayout extends Table{ container.addContainerProperty(METADATA_KEY, String.class, ""); setColumnExpandRatio(METADATA_KEY, 0.7f); setColumnAlignment(METADATA_KEY, Align.LEFT); - + if (permissionChecker.hasUpdateDistributionPermission()) { container.addContainerProperty(VIEW, Label.class, ""); setColumnExpandRatio(VIEW, 0.2F); @@ -154,39 +131,36 @@ public class DistributionSetMetadatadetailslayout extends Table{ setColumnHeader(METADATA_KEY, i18n.get("header.key")); } - - private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata){ + private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata) { final Item item = getContainerDataSource().addItem(dsMetadata.getKey()); item.getItemProperty(METADATA_KEY).setValue(dsMetadata.getKey()); - + } - - private void addCustomGeneratedColumns() { - addGeneratedColumn(METADATA_KEY, - (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); + + private void addCustomGeneratedColumns() { + addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); } private Button customMetadataDetailButton(final String metadataKey) { - final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, "View " - + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); + final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, + "View " + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); viewIcon.setData(metadataKey); viewIcon.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" + " " + "text-style"); viewIcon.addClickListener(event -> showMetadataDetails(selectedDistSetId, metadataKey)); return viewIcon; } - + private static String getDetailLinkId(final String name) { - return new StringBuilder(SPUIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name) - .toString(); + return new StringBuilder(SPUIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name).toString(); } - - private void showMetadataDetails(final Long selectedDistSetId , final String metadataKey) { - DistributionSet distSet = distributionSetManagement.findDistributionSetById(selectedDistSetId); - + + private void showMetadataDetails(final Long selectedDistSetId, final String metadataKey) { + final DistributionSet distSet = distributionSetManagement.findDistributionSetById(selectedDistSetId); + /* display the window */ UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(distSet, - entityFactory.generateDistributionSetMetadata(distSet, metadataKey, "") )); + entityFactory.generateDistributionSetMetadata(distSet, metadataKey, ""))); } - + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java index 854347c11..355080636 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java @@ -80,7 +80,7 @@ public class SoftwareModuleMetadatadetailslayout extends Table { return; } selectedSWModuleId = swModule.getId(); - final List swMetadataList = swModule.getMetadata(); + final List swMetadataList = softwareManagement.findSoftwareModuleMetadataBySoftwareModuleId(selectedSWModuleId); if (null != swMetadataList && !swMetadataList.isEmpty()) { swMetadataList.forEach(swMetadata -> setSWMetadataProperties(swMetadata)); } @@ -160,7 +160,7 @@ public class SoftwareModuleMetadatadetailslayout extends Table { } private void showMetadataDetails(final Long selectedSWModuleId, final String metadataKey) { - SoftwareModule swmodule = softwareManagement.findSoftwareModuleById(selectedSWModuleId); + final SoftwareModule swmodule = softwareManagement.findSoftwareModuleById(selectedSWModuleId); /* display the window */ UI.getCurrent().addWindow( swMetadataPopupLayout.getWindow(swmodule, diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java index 03a86c44d..32deef7a8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java @@ -17,7 +17,6 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModuleIdName; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; @@ -29,7 +28,6 @@ import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable; import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; import org.eclipse.hawkbit.ui.distributions.event.SaveActionWindowEvent; import org.eclipse.hawkbit.ui.distributions.event.SoftwareModuleAssignmentDiscardEvent; import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState; @@ -68,7 +66,7 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet private static final String SOFT_MODULE = "softwareModule"; private static final String UNASSIGN_SOFT_MODULE = "unassignSoftModule"; - + @Autowired private ManageDistUIState manageDistUIState; @@ -83,37 +81,20 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet @Autowired private transient DistributionSetManagement distributionSetManagement; - + @Autowired private DsMetadataPopupLayout dsMetadataPopupLayout; - + @Autowired private EntityFactory entityFactory; private SoftwareModuleDetailsTable softwareModuleTable; - + private DistributionSetMetadatadetailslayout dsMetadataTable; private VerticalLayout tagsLayout; - + private final Map assignedSWModule = new HashMap<>(); - - - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final MetadataEvent event) { - UI.getCurrent() - .access(() -> { - DistributionSetMetadata dsMetadata = event.getDistributionSetMetadata(); - if (dsMetadata != null && isDistributionSetSelected(dsMetadata.getDistributionSet())) { - if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.createMetadata(event.getDistributionSetMetadata().getKey()); - } else if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.deleteMetadata(event.getDistributionSetMetadata().getKey()); - } - } - }); - } - /** * softwareLayout Initialize the component. @@ -124,8 +105,8 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet softwareModuleTable.init(getI18n(), true, getPermissionChecker(), distributionSetManagement, getEventBus(), manageDistUIState); dsMetadataTable = new DistributionSetMetadatadetailslayout(); - dsMetadataTable.init(getI18n(), getPermissionChecker(),distributionSetManagement, - dsMetadataPopupLayout,entityFactory); + dsMetadataTable.init(getI18n(), getPermissionChecker(), distributionSetManagement, dsMetadataPopupLayout, + entityFactory); super.init(); } @@ -141,7 +122,7 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet populateTags(); populateMetadataDetails(); } - + private void populateModule() { softwareModuleTable.populateModule(getSelectedBaseEntity()); showUnsavedAssignment(); @@ -271,12 +252,12 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet updateDistributionSetDetailsLayout(null, null); } } - + @Override - protected void populateMetadataDetails(){ + protected void populateMetadataDetails() { dsMetadataTable.populateDSMetadata(getSelectedBaseEntity()); - } - + } + private void updateDistributionSetDetailsLayout(final String type, final Boolean isMigrationRequired) { final VerticalLayout detailsTabLayout = getDetailsLayout(); detailsTabLayout.removeAllComponents(); @@ -403,26 +384,26 @@ public class DistributionSetDetails extends AbstractNamedVersionedEntityTableDet protected Boolean isMetadataIconToBeDisplayed() { return true; } - + @Override protected String getShowMetadataButtonId() { - DistributionSetIdName lastselectedDistDS = manageDistUIState.getLastSelectedDistribution().isPresent() ? manageDistUIState - .getLastSelectedDistribution().get() : null; + final DistributionSetIdName lastselectedDistDS = manageDistUIState.getLastSelectedDistribution().isPresent() + ? manageDistUIState.getLastSelectedDistribution().get() : null; return SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + lastselectedDistDS.getName() + "." + lastselectedDistDS.getVersion(); } - - private boolean isDistributionSetSelected(DistributionSet ds) { - DistributionSetIdName lastselectedDistDS = manageDistUIState.getLastSelectedDistribution().isPresent() ? manageDistUIState - .getLastSelectedDistribution().get() : null; + + private boolean isDistributionSetSelected(final DistributionSet ds) { + final DistributionSetIdName lastselectedDistDS = manageDistUIState.getLastSelectedDistribution().isPresent() + ? manageDistUIState.getLastSelectedDistribution().get() : null; return ds != null && lastselectedDistDS != null && lastselectedDistDS.getName().equals(ds.getName()) && lastselectedDistDS.getVersion().endsWith(ds.getVersion()); } - @Override - protected void showMetadata(ClickEvent event) { - DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); - UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null)); + protected void showMetadata(final ClickEvent event) { + final DistributionSet ds = distributionSetManagement + .findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); + UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds, null)); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java index 2041944d4..0d433d910 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java @@ -16,8 +16,6 @@ import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.ui.common.AbstractMetadataPopupLayout; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent.MetadataUIEvent; import org.springframework.beans.factory.annotation.Autowired; import com.vaadin.spring.annotation.SpringComponent; @@ -42,19 +40,19 @@ public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout getMetadataList() { return getSelectedEntity().getMetadata(); } - + /** * Update metadata for DistributionSet. */ @Override - protected void deleteMetadata(DistributionSet entity, String key, String value) { - DistributionSetMetadata dsMetaData = entityFactory.generateDistributionSetMetadata(entity, key, value); + protected void deleteMetadata(final DistributionSet entity, final String key, final String value) { + final DistributionSetMetadata dsMetaData = entityFactory.generateDistributionSetMetadata(entity, key, value); distributionSetManagement.deleteDistributionSetMetadata(entity, key); - eventBus.publish(this, new MetadataEvent(MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA, dsMetaData)); } - + @Override protected boolean hasCreatePermission() { return permChecker.hasCreateDistributionPermission(); } - + @Override protected boolean hasUpdatePermission() { return permChecker.hasUpdateDistributionPermission(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java index f82bc5c01..2436de9e5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java @@ -10,6 +10,7 @@ package org.eclipse.hawkbit.ui.distributions.event; import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; + /** * * Metadata Events. @@ -18,21 +19,21 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; public class MetadataEvent { public enum MetadataUIEvent { - CREATE_DISTRIBUTION_SET_METADATA, DELETE_DISTRIBUTION_SET_METADATA, DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA; + DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA; } - private MetadataUIEvent metadataUIEvent; + private final MetadataUIEvent metadataUIEvent; private DistributionSetMetadata distributionSetMetadata; private SoftwareModuleMetadata softwareModuleMetadata; - public MetadataEvent(MetadataUIEvent metadataUIEvent, final DistributionSetMetadata distributionSetMetadata) { + public MetadataEvent(final MetadataUIEvent metadataUIEvent, final DistributionSetMetadata distributionSetMetadata) { this.metadataUIEvent = metadataUIEvent; this.distributionSetMetadata = distributionSetMetadata; } - public MetadataEvent(MetadataUIEvent metadataUIEvent, final SoftwareModuleMetadata softwareModuleMetadata) { + public MetadataEvent(final MetadataUIEvent metadataUIEvent, final SoftwareModuleMetadata softwareModuleMetadata) { this.metadataUIEvent = metadataUIEvent; this.softwareModuleMetadata = softwareModuleMetadata; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java index d83f7b4c8..a4b8c6a86 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java @@ -37,6 +37,7 @@ import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.eclipse.hawkbit.ui.utils.UINotification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,10 +85,6 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { @Autowired private transient EntityFactory entityFactory; - - @Autowired - private transient DistributionSetTable distributionSetTable; - private TextField distNameTextField; private TextField distVersionTextField; private TextArea descTextArea; @@ -239,9 +236,10 @@ public class DistributionAddUpdateWindowLayout extends CustomComponent { notificationMessage.displaySuccess(i18n.get("message.new.dist.save.success", new Object[] { newDist.getName(), newDist.getVersion() })); - + final Set s = new HashSet<>(); - s.add(new DistributionSetIdName(newDist.getId(),newDist.getName(),newDist.getVersion())); + s.add(new DistributionSetIdName(newDist.getId(), newDist.getName(), newDist.getVersion())); + final DistributionSetTable distributionSetTable = SpringContextHelper.getBean(DistributionSetTable.class); distributionSetTable.setValue(s); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java index e59820e9c..b61cc103c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.ui.management.dstable; import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; import org.eclipse.hawkbit.ui.common.DistributionSetIdName; import org.eclipse.hawkbit.ui.common.detailslayout.AbstractNamedVersionedEntityTableDetailsLayout; import org.eclipse.hawkbit.ui.common.detailslayout.DistributionSetMetadatadetailslayout; @@ -19,7 +18,6 @@ import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsTable; import org.eclipse.hawkbit.ui.common.tagdetails.DistributionTagToken; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.distributions.dstable.DsMetadataPopupLayout; -import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; @@ -53,48 +51,32 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail @Autowired private DistributionTagToken distributionTagToken; - + @Autowired - private transient DistributionSetManagement distributionSetManagement; - + private transient DistributionSetManagement distributionSetManagement; + @Autowired private DsMetadataPopupLayout dsMetadataPopupLayout; - + @Autowired private EntityFactory entityFactory; private SoftwareModuleDetailsTable softwareModuleTable; private DistributionSetMetadatadetailslayout dsMetadataTable; - + @Override protected void init() { softwareModuleTable = new SoftwareModuleDetailsTable(); softwareModuleTable.init(getI18n(), false, getPermissionChecker(), null, null, null); - + dsMetadataTable = new DistributionSetMetadatadetailslayout(); - dsMetadataTable.init(getI18n(), getPermissionChecker(),distributionSetManagement, - dsMetadataPopupLayout,entityFactory); - + dsMetadataTable.init(getI18n(), getPermissionChecker(), distributionSetManagement, dsMetadataPopupLayout, + entityFactory); + super.init(); } - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final MetadataEvent event) { - UI.getCurrent() - .access(() -> { - DistributionSetMetadata dsMetadata = event.getDistributionSetMetadata(); - if (dsMetadata != null && isDistributionSetSelected(dsMetadata.getDistributionSet())) { - if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.createMetadata(event.getDistributionSetMetadata().getKey()); - } else if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.deleteMetadata(event.getDistributionSetMetadata().getKey()); - } - } - }); - } - - @EventBusListenerMethod(scope = EventScope.SESSION) void onEvent(final DistributionTableEvent distributionTableEvent) { onBaseEntityEvent(distributionTableEvent); @@ -156,12 +138,11 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail populateMetadataDetails(); } - - + @Override - protected void populateMetadataDetails(){ + protected void populateMetadataDetails() { dsMetadataTable.populateDSMetadata(getSelectedBaseEntity()); - } + } private void populateDetails(final DistributionSet ds) { if (ds != null) { @@ -206,30 +187,32 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail protected String getDetailsHeaderCaptionId() { return SPUIComponentIdProvider.DISTRIBUTION_DETAILS_HEADER_LABEL_ID; } - + @Override protected Boolean isMetadataIconToBeDisplayed() { return true; } - + @Override protected String getShowMetadataButtonId() { - DistributionSetIdName lastselectedDistDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState - .getLastSelectedDistribution().get() : null; + final DistributionSetIdName lastselectedDistDS = managementUIState.getLastSelectedDistribution().isPresent() + ? managementUIState.getLastSelectedDistribution().get() : null; return SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + lastselectedDistDS.getName() + "." + lastselectedDistDS.getVersion(); } - private boolean isDistributionSetSelected(DistributionSet ds) { - DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState - .getLastSelectedDistribution().get() : null; - return ds!=null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) + + private boolean isDistributionSetSelected(final DistributionSet ds) { + final DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() + ? managementUIState.getLastSelectedDistribution().get() : null; + return ds != null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) && lastselectedManageDS.getVersion().endsWith(ds.getVersion()); } @Override - protected void showMetadata(ClickEvent event) { - DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); - UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null)); + protected void showMetadata(final ClickEvent event) { + final DistributionSet ds = distributionSetManagement + .findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); + UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds, null)); } - + } From f2853e6d9fb16be0700c7d3c33ab006c7cf4231d Mon Sep 17 00:00:00 2001 From: Gaurav Date: Thu, 28 Jul 2016 14:24:49 +0200 Subject: [PATCH 04/28] Resolved the conflicts --- .../dstable/DistributionDetails.java | 37 +------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java index 68a65ab45..6dc1d7a69 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java @@ -76,25 +76,6 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail super.init(); } -<<<<<<< HEAD -======= - - @EventBusListenerMethod(scope = EventScope.SESSION) - void onEvent(final MetadataEvent event) { - UI.getCurrent() - .access(() -> { - final DistributionSetMetadata dsMetadata = event.getDistributionSetMetadata(); - if (dsMetadata != null && isDistributionSetSelected(dsMetadata.getDistributionSet())) { - if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.createMetadata(event.getDistributionSetMetadata().getKey()); - } else if (event.getMetadataUIEvent() == MetadataEvent.MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA) { - dsMetadataTable.deleteMetadata(event.getDistributionSetMetadata().getKey()); - } - } - }); - } - ->>>>>>> refs/heads/master @EventBusListenerMethod(scope = EventScope.SESSION) void onEvent(final DistributionTableEvent distributionTableEvent) { @@ -214,41 +195,25 @@ public class DistributionDetails extends AbstractNamedVersionedEntityTableDetail @Override protected String getShowMetadataButtonId() { -<<<<<<< HEAD final DistributionSetIdName lastselectedDistDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState.getLastSelectedDistribution().get() : null; -======= - final DistributionSetIdName lastselectedDistDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState - .getLastSelectedDistribution().get() : null; ->>>>>>> refs/heads/master + return SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + lastselectedDistDS.getName() + "." + lastselectedDistDS.getVersion(); } -<<<<<<< HEAD private boolean isDistributionSetSelected(final DistributionSet ds) { final DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState.getLastSelectedDistribution().get() : null; return ds != null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) -======= - private boolean isDistributionSetSelected(final DistributionSet ds) { - final DistributionSetIdName lastselectedManageDS = managementUIState.getLastSelectedDistribution().isPresent() ? managementUIState - .getLastSelectedDistribution().get() : null; - return ds!=null && lastselectedManageDS != null && lastselectedManageDS.getName().equals(ds.getName()) ->>>>>>> refs/heads/master && lastselectedManageDS.getVersion().endsWith(ds.getVersion()); } @Override protected void showMetadata(final ClickEvent event) { -<<<<<<< HEAD final DistributionSet ds = distributionSetManagement .findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds, null)); -======= - final DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(getSelectedBaseEntityId()); - UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null)); ->>>>>>> refs/heads/master } } From e32d6b1b3eb866f81f0ec430c4317a1670535af6 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Fri, 29 Jul 2016 12:33:10 +0200 Subject: [PATCH 05/28] Modified EOL from windows to unix. --- .../repository/DistributionSetManagement.java | 1216 +++++++-------- .../repository/SoftwareManagement.java | 1008 ++++++------- .../repository/jpa/JpaSoftwareManagement.java | 1344 ++++++++--------- .../repository/jpa/model/JpaAction.java | 398 ++--- .../jpa/model/JpaDistributionSet.java | 640 ++++---- .../repository/jpa/model/JpaRollout.java | 446 +++--- .../repository/jpa/model/JpaRolloutGroup.java | 522 +++---- .../repository/jpa/model/JpaTarget.java | 514 +++---- .../repository/jpa/model/JpaTargetInfo.java | 688 ++++----- 9 files changed, 3388 insertions(+), 3388 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index f7566b86b..b3b4fd86f 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -1,608 +1,608 @@ -/** - * 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; - -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.DistributionSetFilter; -import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; -import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Tag; -import org.eclipse.hawkbit.repository.model.Target; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.security.access.prepost.PreAuthorize; - -/** - * Management service for {@link DistributionSet}s. - * - */ -public interface DistributionSetManagement { - - // TODO rename/document the whole with details thing (document what the - // details are and maybe find a better name, e.g. with dependencies?) - - /** - * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. - * - * @param ds - * to assign and update - * @param softwareModules - * to get assigned - * @return the updated {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet assignSoftwareModules(@NotNull DistributionSet ds, Set softwareModules); - - /** - * Assign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s. - * - * @param dsIds - * to assign for - * @param tag - * to assign - * @return list of assigned ds - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List assignTag(@NotEmpty Collection dsIds, @NotNull DistributionSetTag tag); - - /** - * Count all {@link DistributionSet}s in the repository that are not marked - * as deleted. - * - * @return number of {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetsAll(); - - /** - * Count all {@link DistributionSet}s in the repository that are not marked - * as deleted. - * - * @param type - * to look for - * - * @return number of {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetsByType(@NotNull DistributionSetType type); - - /** - * @return number of {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countDistributionSetTypesAll(); - - /** - * Creates a new {@link DistributionSet}. - * - * @param dSet - * {@link DistributionSet} to be created - * @return the new persisted {@link DistributionSet} - * - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - DistributionSet createDistributionSet(@NotNull DistributionSet dSet); - - /** - * creates a list of distribution set meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created distribution set meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List createDistributionSetMetadata(@NotEmpty Collection metadata); - - /** - * creates or updates a single distribution set meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created distribution set meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetMetadata createDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); - - /** - * Creates multiple {@link DistributionSet}s. - * - * @param distributionSets - * to be created - * @return the new {@link DistributionSet}s - * @throws EntityAlreadyExistsException - * if a given entity already exists - * @throws DistributionSetCreationFailedMissingMandatoryModuleException - * is {@link DistributionSet} does not contain mandatory - * {@link SoftwareModule}s. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createDistributionSets(@NotNull Collection distributionSets); - - /** - * Creates new {@link DistributionSetType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - DistributionSetType createDistributionSetType(@NotNull DistributionSetType type); - - /** - * Creates multiple {@link DistributionSetType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createDistributionSetTypes(@NotNull Collection types); - - /** - *

- * {@link DistributionSet} can be deleted/erased from the repository if they - * have never been assigned to any {@link UpdateAction} or {@link Target}. - *

- * - *

- * If they have been assigned that need to be marked as deleted which as a - * result means that they cannot be assigned anymore to any targets. (define - * e.g. findByDeletedFalse()) - *

- * - * @param set - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSet(@NotNull DistributionSet set); - - /** - * Deleted {@link DistributionSet}s by their IDs. That is either a soft - * delete of the entities have been linked to an {@link UpdateAction} before - * or a hard delete if not. - * - * @param distributionSetIDs - * to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSet(@NotEmpty Long... distributionSetIDs); - - /** - * deletes a distribution set meta data entry. - * - * @param id - * the ID of the distribution set meta data to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key); - - /** - * Deletes or mark as delete in case the type is in use. - * - * @param type - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteDistributionSetType(@NotNull DistributionSetType type); - - /** - * retrieves the distribution set for a given action. - * - * @param action - * the action associated with the distribution set - * @return the distribution set which is associated with the action - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByAction(@NotNull Action action); - - /** - * Find {@link DistributionSet} based on given ID without details, e.g. - * {@link DistributionSet#getAgentHub()}. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetById(@NotNull Long distid); - - /** - * Find {@link DistributionSet} based on given ID including (lazy loaded) - * details, e.g. {@link DistributionSet#getAgentHub()}. - * - * Note: for performance reasons it is recommended to use - * {@link #findDistributionSetById(Long)} if details are not necessary. - * - * @param distid - * to look for. - * @return {@link DistributionSet} or null if it does not exist - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByIdWithDetails(@NotNull Long distid); - - /** - * Find distribution set by name and version. - * - * @param distributionName - * name of {@link DistributionSet}; case insensitive - * @param version - * version of {@link DistributionSet} - * @return the page with the found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSet findDistributionSetByNameAndVersion(@NotEmpty String distributionName, @NotEmpty String version); - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, - @NotNull Pageable pageable); - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @return list of distributionSetMetadata for a given distribution set Id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - List findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId); - - /** - * finds all meta data by the given distribution set id. - * - * @param distributionSetId - * the distribution set id to retrieve the meta data from - * @param rsqlParam - * rsql query string - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given distribution - * set id - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, - @NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Retrieves {@link DistributionSet} List for overview purposes (no - * {@link SoftwareModule}s and {@link DistributionSetTag}s). - * - * Please use {@link #findDistributionSetListWithDetails(Iterable)} if - * details are required. - * - * @param dist - * List of {@link DistributionSet} IDs to be found - * @return the found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - List findDistributionSetsAll(Collection dist); - - // TODO discuss: use enum instead of the true,false,null switch ? - /** - * finds all {@link DistributionSet}s. - * - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @param complete - * to true for returning only completed distribution - * sets or false for only incomplete ones nor - * null to return both. - * @param complete - * set to if false incomplete DS should also be - * shown. - * - * - * @return all found {@link DistributionSet}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsByDeletedAndOrCompleted(@NotNull Pageable pageReq, Boolean deleted, - Boolean complete); - - /** - * finds all {@link DistributionSet}s. - * - * @param rsqlParam - * rsql query string - * @param pageReq - * the pagination parameter - * @param deleted - * if TRUE, {@link DistributionSet}s marked as deleted are - * returned. If FALSE, on {@link DistributionSet}s with - * {@link DistributionSet#isDeleted()} == FALSE are returned. - * null if both are to be returned - * @return all found {@link DistributionSet}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsAll(@NotNull String rsqlParam, @NotNull Pageable pageReq, - Boolean deleted); - - /** - * method retrieves all {@link DistributionSet}s from the repository in the - * following order: - *

- * 1) {@link DistributionSet}s which have the given {@link Target} as - * {@link TargetStatus#getInstalledDistributionSet()} - *

- * 2) {@link DistributionSet}s which have the given {@link Target} as - * {@link Target#getAssignedDistributionSet()} - *

- * 3) {@link DistributionSet}s which have no connection to the given - * {@link Target} ordered by ID of the DistributionSet. - * - * @param pageable - * the page request to page the result set * - * @param distributionSetFilterBuilder - * has details of filters to be applied - * @param assignedOrInstalled - * the controllerID of the Target to be ordered by - * @return - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsAllOrderedByLinkTarget(@NotNull Pageable pageable, - @NotNull DistributionSetFilterBuilder distributionSetFilterBuilder, @NotEmpty String assignedOrInstalled); - - /** - * retrieves {@link DistributionSet}s by filtering on the given parameters. - * - * @param pageable - * page parameter - * @param distributionSetFilter - * has details of filters to be applied. - * @return the page of found {@link DistributionSet} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetsByFilters(@NotNull Pageable pageable, - @NotNull DistributionSetFilter distributionSetFilter); - - /** - * @param id - * as {@link DistributionSetType#getId()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeById(@NotNull Long id); - - /** - * @param key - * as {@link DistributionSetType#getKey()} - * @return {@link DistributionSetType} if found or null if not - */ - - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeByKey(@NotNull String key); - - /** - * @param name - * as {@link DistributionSetType#getName()} - * @return {@link DistributionSetType} if found or null if not - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetType findDistributionSetTypeByName(@NotEmpty String name); - - /** - * @param pageable - * parameter - * @return all {@link DistributionSetType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetTypesAll(@NotNull Pageable pageable); - - /** - * Generic predicate based query for {@link DistributionSetType}. - * - * @param rsqlParam - * rsql query string - * @param pageable - * parameter for paging - * - * @return the found {@link SoftwareModuleType}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findDistributionSetTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * finds a single distribution set meta data by its id. - * - * @param id - * the id of the distribution set meta data containing the meta - * data key and the ID of the distribution set - * @return the found DistributionSetMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key); - - /** - * Checks if a {@link DistributionSet} is currently in use by a target in - * the repository. - * - * @param distributionSet - * to check - * - * @return true if in use - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - boolean isDistributionSetInUse(@NotNull DistributionSet distributionSet); - - /** - * {@link Entity} based method call for - * {@link #toggleTagAssignment(Collection, String)}. - * - * @param sets - * to toggle for - * @param tag - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection sets, - @NotNull DistributionSetTag tag); - - /** - * Toggles {@link DistributionSetTag} assignment to given - * {@link DistributionSet}s by means that if some (or all) of the targets in - * the list have the {@link Tag} not yet assigned, they will be. If all of - * theme have the tag already assigned they will be removed instead. - * - * @param dsIds - * to toggle for - * @param tagName - * to toggle - * @return {@link DistributionSetTagAssignmentResult} with all meta data of - * the assignment outcome. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection dsIds, @NotNull String tagName); - - /** - * Unassign all {@link DistributionSet} from a given - * {@link DistributionSetTag} . - * - * @param tag - * to unassign all ds - * @return list of unassigned ds - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List unAssignAllDistributionSetsByTag(@NotNull DistributionSetTag tag); - - /** - * Unassigns a {@link SoftwareModule} form an existing - * {@link DistributionSet}. - * - * @param ds - * to get unassigned form - * @param softwareModule - * to get unassigned - * @return the updated {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet unassignSoftwareModule(@NotNull DistributionSet ds, @NotNull SoftwareModule softwareModule); - - /** - * Unassign a {@link DistributionSetTag} assignment to given - * {@link DistributionSet}. - * - * @param dsId - * to unassign for - * @param distributionSetTag - * to unassign - * @return the unassigned ds or if no ds is unassigned - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet unAssignTag(@NotNull Long dsId, @NotNull DistributionSetTag distributionSetTag); - - /** - * Updates existing {@link DistributionSet}. - * - * @param ds - * to update - * @return the saved {@link Entity}. - * @throws NullPointerException - * of {@link DistributionSet#getId()} is null - * @throw DataDependencyViolationException in case of illegal update - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSet updateDistributionSet(@NotNull DistributionSet ds); - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetMetadata updateDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); - - /** - * Updates existing {@link DistributionSetType}. However, keep in mind that - * is not possible to change the {@link DistributionSetTypeElement}s while - * the DS type is already in use. - * - * @param dsType - * to update - * @return updated {@link Entity} - * - * @throws EntityReadOnlyException - * if use tries to change the {@link DistributionSetTypeElement} - * s while the DS type is already in use. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - DistributionSetType updateDistributionSetType(@NotNull DistributionSetType dsType); - -} +/** + * 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; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.DistributionSetCreationFailedMissingMandatoryModuleException; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter; +import org.eclipse.hawkbit.repository.model.DistributionSetFilter.DistributionSetFilterBuilder; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Tag; +import org.eclipse.hawkbit.repository.model.Target; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Management service for {@link DistributionSet}s. + * + */ +public interface DistributionSetManagement { + + // TODO rename/document the whole with details thing (document what the + // details are and maybe find a better name, e.g. with dependencies?) + + /** + * Assigns {@link SoftwareModule} to existing {@link DistributionSet}. + * + * @param ds + * to assign and update + * @param softwareModules + * to get assigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet assignSoftwareModules(@NotNull DistributionSet ds, Set softwareModules); + + /** + * Assign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s. + * + * @param dsIds + * to assign for + * @param tag + * to assign + * @return list of assigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List assignTag(@NotEmpty Collection dsIds, @NotNull DistributionSetTag tag); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsAll(); + + /** + * Count all {@link DistributionSet}s in the repository that are not marked + * as deleted. + * + * @param type + * to look for + * + * @return number of {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetsByType(@NotNull DistributionSetType type); + + /** + * @return number of {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countDistributionSetTypesAll(); + + /** + * Creates a new {@link DistributionSet}. + * + * @param dSet + * {@link DistributionSet} to be created + * @return the new persisted {@link DistributionSet} + * + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSet createDistributionSet(@NotNull DistributionSet dSet); + + /** + * creates a list of distribution set meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created distribution set meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createDistributionSetMetadata(@NotEmpty Collection metadata); + + /** + * creates or updates a single distribution set meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created distribution set meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata createDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Creates multiple {@link DistributionSet}s. + * + * @param distributionSets + * to be created + * @return the new {@link DistributionSet}s + * @throws EntityAlreadyExistsException + * if a given entity already exists + * @throws DistributionSetCreationFailedMissingMandatoryModuleException + * is {@link DistributionSet} does not contain mandatory + * {@link SoftwareModule}s. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSets(@NotNull Collection distributionSets); + + /** + * Creates new {@link DistributionSetType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + DistributionSetType createDistributionSetType(@NotNull DistributionSetType type); + + /** + * Creates multiple {@link DistributionSetType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createDistributionSetTypes(@NotNull Collection types); + + /** + *

+ * {@link DistributionSet} can be deleted/erased from the repository if they + * have never been assigned to any {@link UpdateAction} or {@link Target}. + *

+ * + *

+ * If they have been assigned that need to be marked as deleted which as a + * result means that they cannot be assigned anymore to any targets. (define + * e.g. findByDeletedFalse()) + *

+ * + * @param set + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotNull DistributionSet set); + + /** + * Deleted {@link DistributionSet}s by their IDs. That is either a soft + * delete of the entities have been linked to an {@link UpdateAction} before + * or a hard delete if not. + * + * @param distributionSetIDs + * to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSet(@NotEmpty Long... distributionSetIDs); + + /** + * deletes a distribution set meta data entry. + * + * @param id + * the ID of the distribution set meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key); + + /** + * Deletes or mark as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteDistributionSetType(@NotNull DistributionSetType type); + + /** + * retrieves the distribution set for a given action. + * + * @param action + * the action associated with the distribution set + * @return the distribution set which is associated with the action + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByAction(@NotNull Action action); + + /** + * Find {@link DistributionSet} based on given ID without details, e.g. + * {@link DistributionSet#getAgentHub()}. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetById(@NotNull Long distid); + + /** + * Find {@link DistributionSet} based on given ID including (lazy loaded) + * details, e.g. {@link DistributionSet#getAgentHub()}. + * + * Note: for performance reasons it is recommended to use + * {@link #findDistributionSetById(Long)} if details are not necessary. + * + * @param distid + * to look for. + * @return {@link DistributionSet} or null if it does not exist + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByIdWithDetails(@NotNull Long distid); + + /** + * Find distribution set by name and version. + * + * @param distributionName + * name of {@link DistributionSet}; case insensitive + * @param version + * version of {@link DistributionSet} + * @return the page with the found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSet findDistributionSetByNameAndVersion(@NotEmpty String distributionName, @NotEmpty String version); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @return list of distributionSetMetadata for a given distribution set Id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId); + + /** + * finds all meta data by the given distribution set id. + * + * @param distributionSetId + * the distribution set id to retrieve the meta data from + * @param rsqlParam + * rsql query string + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given distribution + * set id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves {@link DistributionSet} List for overview purposes (no + * {@link SoftwareModule}s and {@link DistributionSetTag}s). + * + * Please use {@link #findDistributionSetListWithDetails(Iterable)} if + * details are required. + * + * @param dist + * List of {@link DistributionSet} IDs to be found + * @return the found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findDistributionSetsAll(Collection dist); + + // TODO discuss: use enum instead of the true,false,null switch ? + /** + * finds all {@link DistributionSet}s. + * + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @param complete + * to true for returning only completed distribution + * sets or false for only incomplete ones nor + * null to return both. + * @param complete + * set to if false incomplete DS should also be + * shown. + * + * + * @return all found {@link DistributionSet}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByDeletedAndOrCompleted(@NotNull Pageable pageReq, Boolean deleted, + Boolean complete); + + /** + * finds all {@link DistributionSet}s. + * + * @param rsqlParam + * rsql query string + * @param pageReq + * the pagination parameter + * @param deleted + * if TRUE, {@link DistributionSet}s marked as deleted are + * returned. If FALSE, on {@link DistributionSet}s with + * {@link DistributionSet#isDeleted()} == FALSE are returned. + * null if both are to be returned + * @return all found {@link DistributionSet}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAll(@NotNull String rsqlParam, @NotNull Pageable pageReq, + Boolean deleted); + + /** + * method retrieves all {@link DistributionSet}s from the repository in the + * following order: + *

+ * 1) {@link DistributionSet}s which have the given {@link Target} as + * {@link TargetStatus#getInstalledDistributionSet()} + *

+ * 2) {@link DistributionSet}s which have the given {@link Target} as + * {@link Target#getAssignedDistributionSet()} + *

+ * 3) {@link DistributionSet}s which have no connection to the given + * {@link Target} ordered by ID of the DistributionSet. + * + * @param pageable + * the page request to page the result set * + * @param distributionSetFilterBuilder + * has details of filters to be applied + * @param assignedOrInstalled + * the controllerID of the Target to be ordered by + * @return + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsAllOrderedByLinkTarget(@NotNull Pageable pageable, + @NotNull DistributionSetFilterBuilder distributionSetFilterBuilder, @NotEmpty String assignedOrInstalled); + + /** + * retrieves {@link DistributionSet}s by filtering on the given parameters. + * + * @param pageable + * page parameter + * @param distributionSetFilter + * has details of filters to be applied. + * @return the page of found {@link DistributionSet} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetsByFilters(@NotNull Pageable pageable, + @NotNull DistributionSetFilter distributionSetFilter); + + /** + * @param id + * as {@link DistributionSetType#getId()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeById(@NotNull Long id); + + /** + * @param key + * as {@link DistributionSetType#getKey()} + * @return {@link DistributionSetType} if found or null if not + */ + + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByKey(@NotNull String key); + + /** + * @param name + * as {@link DistributionSetType#getName()} + * @return {@link DistributionSetType} if found or null if not + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetType findDistributionSetTypeByName(@NotEmpty String name); + + /** + * @param pageable + * parameter + * @return all {@link DistributionSetType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull Pageable pageable); + + /** + * Generic predicate based query for {@link DistributionSetType}. + * + * @param rsqlParam + * rsql query string + * @param pageable + * parameter for paging + * + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findDistributionSetTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * finds a single distribution set meta data by its id. + * + * @param id + * the id of the distribution set meta data containing the meta + * data key and the ID of the distribution set + * @return the found DistributionSetMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key); + + /** + * Checks if a {@link DistributionSet} is currently in use by a target in + * the repository. + * + * @param distributionSet + * to check + * + * @return true if in use + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + boolean isDistributionSetInUse(@NotNull DistributionSet distributionSet); + + /** + * {@link Entity} based method call for + * {@link #toggleTagAssignment(Collection, String)}. + * + * @param sets + * to toggle for + * @param tag + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection sets, + @NotNull DistributionSetTag tag); + + /** + * Toggles {@link DistributionSetTag} assignment to given + * {@link DistributionSet}s by means that if some (or all) of the targets in + * the list have the {@link Tag} not yet assigned, they will be. If all of + * theme have the tag already assigned they will be removed instead. + * + * @param dsIds + * to toggle for + * @param tagName + * to toggle + * @return {@link DistributionSetTagAssignmentResult} with all meta data of + * the assignment outcome. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection dsIds, @NotNull String tagName); + + /** + * Unassign all {@link DistributionSet} from a given + * {@link DistributionSetTag} . + * + * @param tag + * to unassign all ds + * @return list of unassigned ds + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List unAssignAllDistributionSetsByTag(@NotNull DistributionSetTag tag); + + /** + * Unassigns a {@link SoftwareModule} form an existing + * {@link DistributionSet}. + * + * @param ds + * to get unassigned form + * @param softwareModule + * to get unassigned + * @return the updated {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unassignSoftwareModule(@NotNull DistributionSet ds, @NotNull SoftwareModule softwareModule); + + /** + * Unassign a {@link DistributionSetTag} assignment to given + * {@link DistributionSet}. + * + * @param dsId + * to unassign for + * @param distributionSetTag + * to unassign + * @return the unassigned ds or if no ds is unassigned + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet unAssignTag(@NotNull Long dsId, @NotNull DistributionSetTag distributionSetTag); + + /** + * Updates existing {@link DistributionSet}. + * + * @param ds + * to update + * @return the saved {@link Entity}. + * @throws NullPointerException + * of {@link DistributionSet#getId()} is null + * @throw DataDependencyViolationException in case of illegal update + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSet updateDistributionSet(@NotNull DistributionSet ds); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetMetadata updateDistributionSetMetadata(@NotNull DistributionSetMetadata metadata); + + /** + * Updates existing {@link DistributionSetType}. However, keep in mind that + * is not possible to change the {@link DistributionSetTypeElement}s while + * the DS type is already in use. + * + * @param dsType + * to update + * @return updated {@link Entity} + * + * @throws EntityReadOnlyException + * if use tries to change the {@link DistributionSetTypeElement} + * s while the DS type is already in use. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + DistributionSetType updateDistributionSetType(@NotNull DistributionSetType dsType); + +} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index e48aaa3ab..bb73dbb30 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -1,504 +1,504 @@ -/** - * 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; - -import java.util.Collection; -import java.util.List; - -import javax.validation.constraints.NotNull; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; -import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; -import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.hibernate.validator.constraints.NotEmpty; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.security.access.prepost.PreAuthorize; - -/** - * Service for managing {@link SoftwareModule}s. - * - */ -public interface SoftwareManagement { - - /** - * Counts {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param searchText - * to search for in name and version - * @param type - * to filter the result - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModuleByFilters(String searchText, SoftwareModuleType type); - - /** - * Count all {@link SoftwareModule}s in the repository that are not marked - * as deleted. - * - * @return number of {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModulesAll(); - - /** - * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. - * - * @param type - * to count - * @return number of found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModulesByType(@NotNull SoftwareModuleType type); - - /** - * @return number of {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Long countSoftwareModuleTypesAll(); - - /** - * Create {@link SoftwareModule}s in the repository. - * - * @param swModules - * {@link SoftwareModule}s to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createSoftwareModule(@NotNull Collection swModules); - - /** - * - * @param swModule - * SoftwareModule to create - * @return SoftwareModule - * @throws EntityAlreadyExistsException - * if a given entity already exists - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - SoftwareModule createSoftwareModule(@NotNull SoftwareModule swModule); - - /** - * creates a list of software module meta data entries. - * - * @param metadata - * the meta data entries to create or update - * @return the updated or created software module meta data entries - * @throws EntityAlreadyExistsException - * in case one of the meta data entry already exists for the - * specific key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - List createSoftwareModuleMetadata(@NotNull Collection metadata); - - /** - * creates or updates a single software module meta data entry. - * - * @param metadata - * the meta data entry to create or update - * @return the updated or created software module meta data entry - * @throws EntityAlreadyExistsException - * in case the meta data entry already exists for the specific - * key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); - - /** - * Creates multiple {@link SoftwareModuleType}s. - * - * @param types - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - List createSoftwareModuleType(@NotNull final Collection types); - - /** - * Creates new {@link SoftwareModuleType}. - * - * @param type - * to create - * @return created {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) - SoftwareModuleType createSoftwareModuleType(@NotNull SoftwareModuleType type); - - /** - * Deletes the given {@link SoftwareModule} {@link Entity}. - * - * @param bsm - * is the {@link SoftwareModule} to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModule(@NotNull SoftwareModule bsm); - - /** - * deletes a software module meta data entry. - * - * @param id - * the ID of the software module meta data to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key); - - /** - * Deletes {@link SoftwareModule}s which is any if the given ids. - * - * @param ids - * of the Software Modules to be deleted - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModules(@NotNull Collection ids); - - /** - * Deletes or marks as delete in case the type is in use. - * - * @param type - * to delete - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) - void deleteSoftwareModuleType(@NotNull SoftwareModuleType type); - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleByAssignedTo(@NotNull Pageable pageable, @NotNull DistributionSet set); - - /** - * @param pageable - * the page request to page the result set - * @param set - * to search for - * @param type - * to filter - * @return all {@link SoftwareModule}s that are assigned to given - * {@link DistributionSet} filtered by {@link SoftwareModuleType}. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleByAssignedToAndType(@NotNull Pageable pageable, @NotNull DistributionSet set, - @NotNull SoftwareModuleType type); - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * and {@link SoftwareModule#getType()} that are not marked as deleted. - * - * @param pageable - * page parameter - * @param searchText - * to be filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * to be filtered as "like" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModuleByFilters(@NotNull Pageable pageable, String searchText, - SoftwareModuleType type); - - /** - * Finds {@link SoftwareModule} by given id. - * - * @param id - * to search for - * @return the found {@link SoftwareModule}s or null if not - * found. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR - + SpringEvalExpressions.IS_CONTROLLER) - SoftwareModule findSoftwareModuleById(@NotNull Long id); - - /** - * retrieves {@link SoftwareModule} by their name AND version AND type.. - * - * @param name - * of the {@link SoftwareModule} - * @param version - * of the {@link SoftwareModule} - * @param type - * of the {@link SoftwareModule} - * @return the found {@link SoftwareModule} or null - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty String name, @NotEmpty String version, - @NotNull SoftwareModuleType type); - - /** - * finds a single software module meta data by its id. - * - * @param id - * the id of the software module meta data containing the meta - * data key and the ID of the software module - * @return the found SoftwareModuleMetadata or {@code null} if not exits - * @throws EntityNotFoundException - * in case the meta data does not exists for the given key - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key); - - /** - * finds all meta data by the given software module id. - * - * @param swId - * the software module id to retrieve the meta data from - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long swId, - @NotNull Pageable pageable); - - /** - * finds all meta data by the given software module id. - * - * @param softwareModuleId - * the software module id to retrieve the meta data from - * @param spec - * the specification to filter the result - * @param pageable - * the page request to page the result - * @return a paged result of all meta data entries for a given software - * module id - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long softwareModuleId, - @NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Filter {@link SoftwareModule}s with given - * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} - * search text and {@link SoftwareModule#getType()} that are not marked as - * deleted and sort them by means of given distribution set related modules - * on top of the list. - * - * After that the modules are sorted by {@link SoftwareModule#getName()} and - * {@link SoftwareModule#getVersion()} in ascending order. - * - * @param pageable - * page parameter - * @param orderByDistributionId - * the ID of distribution set to be ordered on top - * @param searchText - * filtered as "like" on {@link SoftwareModule#getName()} - * @param type - * filtered as "equal" on {@link SoftwareModule#getType()} - * @return the page of found {@link SoftwareModule} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( - @NotNull Pageable pageable, @NotNull Long orderByDistributionId, String searchText, - SoftwareModuleType type); - - /** - * Retrieves all software modules. Deleted ones are filtered. - * - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModulesAll(@NotNull Pageable pageable); - - /** - * Retrieves all software modules with a given list of ids - * {@link SoftwareModule#getId()}. - * - * @param ids - * to search for - * @return {@link List} of found {@link SoftwareModule}s - */ - List findSoftwareModulesById(@NotEmpty Collection ids); - - /** - * Retrieves all {@link SoftwareModule}s with a given specification. - * - * @param spec - * the specification to filter the software modules - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModule}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModulesByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} - * . - * - * @param pageable - * page parameters - * @param type - * to be filtered on - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Slice findSoftwareModulesByType(@NotNull Pageable pageable, @NotNull SoftwareModuleType type); - - /** - * - * @param id - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getId()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeById(@NotNull Long id); - - /** - * - * @param key - * to search for - * @return {@link SoftwareModuleType} in the repository with given - * {@link SoftwareModuleType#getKey()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key); - - /** - * - * @param name - * to search for - * @return all {@link SoftwareModuleType}s in the repository with given - * {@link SoftwareModuleType#getName()} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModuleType findSoftwareModuleTypeByName(@NotNull String name); - - /** - * @param pageable - * parameter - * @return all {@link SoftwareModuleType}s in the repository. - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleTypesAll(@NotNull Pageable pageable); - - /** - * Retrieves all {@link SoftwareModuleType}s with a given specification. - * - * @param spec - * the specification to filter the software modules types - * @param pageable - * pagination parameter - * @return the found {@link SoftwareModuleType}s - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - Page findSoftwareModuleTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); - - /** - * Retrieves software module including details ( - * {@link SoftwareModule#getArtifacts()}). - * - * @param id - * parameter - * @param isDeleted - * parameter - * @return the found {@link SoftwareModule}s - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); - - /** - * Updates existing {@link SoftwareModule}. Update-able values are - * {@link SoftwareModule#getDescription()} - * {@link SoftwareModule#getVendor()}. - * - * @param sm - * to update - * - * @return the saved {@link Entity}. - * - * @throws NullPointerException - * of {@link SoftwareModule#getId()} is null - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModule updateSoftwareModule(@NotNull SoftwareModule sm); - - /** - * updates a distribution set meta data value if corresponding entry exists. - * - * @param metadata - * the meta data entry to be updated - * @return the updated meta data entry - * @throws EntityNotFoundException - * in case the meta data entry does not exists and cannot be - * updated - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); - - /** - * Updates existing {@link SoftwareModuleType}. Update-able value is - * {@link SoftwareModuleType#getDescription()} and - * {@link SoftwareModuleType#getColour()}. - * - * @param sm - * to update - * @return updated {@link Entity} - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) - SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); - - /** - * finds all meta data by the given software module id. - * - * @param softwareModuleId - * the software module id to retrieve the meta data from - - * - * @throws RSQLParameterUnsupportedFieldException - * if a field in the RSQL string is used but not provided by the - * given {@code fieldNameProvider} - * @throws RSQLParameterSyntaxException - * if the RSQL syntax is wrong - * @return result of all meta data entries for a given software - * module id - */ - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - List findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId); - -} +/** + * 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; + +import java.util.Collection; +import java.util.List; + +import javax.validation.constraints.NotNull; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException; +import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.access.prepost.PreAuthorize; + +/** + * Service for managing {@link SoftwareModule}s. + * + */ +public interface SoftwareManagement { + + /** + * Counts {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param searchText + * to search for in name and version + * @param type + * to filter the result + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleByFilters(String searchText, SoftwareModuleType type); + + /** + * Count all {@link SoftwareModule}s in the repository that are not marked + * as deleted. + * + * @return number of {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesAll(); + + /** + * Counts {@link SoftwareModule}s with given {@link SoftwareModuleType}. + * + * @param type + * to count + * @return number of found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModulesByType(@NotNull SoftwareModuleType type); + + /** + * @return number of {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Long countSoftwareModuleTypesAll(); + + /** + * Create {@link SoftwareModule}s in the repository. + * + * @param swModules + * {@link SoftwareModule}s to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModule(@NotNull Collection swModules); + + /** + * + * @param swModule + * SoftwareModule to create + * @return SoftwareModule + * @throws EntityAlreadyExistsException + * if a given entity already exists + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModule createSoftwareModule(@NotNull SoftwareModule swModule); + + /** + * creates a list of software module meta data entries. + * + * @param metadata + * the meta data entries to create or update + * @return the updated or created software module meta data entries + * @throws EntityAlreadyExistsException + * in case one of the meta data entry already exists for the + * specific key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + List createSoftwareModuleMetadata(@NotNull Collection metadata); + + /** + * creates or updates a single software module meta data entry. + * + * @param metadata + * the meta data entry to create or update + * @return the updated or created software module meta data entry + * @throws EntityAlreadyExistsException + * in case the meta data entry already exists for the specific + * key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata createSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Creates multiple {@link SoftwareModuleType}s. + * + * @param types + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + List createSoftwareModuleType(@NotNull final Collection types); + + /** + * Creates new {@link SoftwareModuleType}. + * + * @param type + * to create + * @return created {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY) + SoftwareModuleType createSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * Deletes the given {@link SoftwareModule} {@link Entity}. + * + * @param bsm + * is the {@link SoftwareModule} to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModule(@NotNull SoftwareModule bsm); + + /** + * deletes a software module meta data entry. + * + * @param id + * the ID of the software module meta data to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key); + + /** + * Deletes {@link SoftwareModule}s which is any if the given ids. + * + * @param ids + * of the Software Modules to be deleted + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModules(@NotNull Collection ids); + + /** + * Deletes or marks as delete in case the type is in use. + * + * @param type + * to delete + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY) + void deleteSoftwareModuleType(@NotNull SoftwareModuleType type); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedTo(@NotNull Pageable pageable, @NotNull DistributionSet set); + + /** + * @param pageable + * the page request to page the result set + * @param set + * to search for + * @param type + * to filter + * @return all {@link SoftwareModule}s that are assigned to given + * {@link DistributionSet} filtered by {@link SoftwareModuleType}. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleByAssignedToAndType(@NotNull Pageable pageable, @NotNull DistributionSet set, + @NotNull SoftwareModuleType type); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * and {@link SoftwareModule#getType()} that are not marked as deleted. + * + * @param pageable + * page parameter + * @param searchText + * to be filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * to be filtered as "like" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleByFilters(@NotNull Pageable pageable, String searchText, + SoftwareModuleType type); + + /** + * Finds {@link SoftwareModule} by given id. + * + * @param id + * to search for + * @return the found {@link SoftwareModule}s or null if not + * found. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR + + SpringEvalExpressions.IS_CONTROLLER) + SoftwareModule findSoftwareModuleById(@NotNull Long id); + + /** + * retrieves {@link SoftwareModule} by their name AND version AND type.. + * + * @param name + * of the {@link SoftwareModule} + * @param version + * of the {@link SoftwareModule} + * @param type + * of the {@link SoftwareModule} + * @return the found {@link SoftwareModule} or null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleByNameAndVersion(@NotEmpty String name, @NotEmpty String version, + @NotNull SoftwareModuleType type); + + /** + * finds a single software module meta data by its id. + * + * @param id + * the id of the software module meta data containing the meta + * data key and the ID of the software module + * @return the found SoftwareModuleMetadata or {@code null} if not exits + * @throws EntityNotFoundException + * in case the meta data does not exists for the given key + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleMetadata findSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key); + + /** + * finds all meta data by the given software module id. + * + * @param swId + * the software module id to retrieve the meta data from + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long swId, + @NotNull Pageable pageable); + + /** + * finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + * @param spec + * the specification to filter the result + * @param pageable + * the page request to page the result + * @return a paged result of all meta data entries for a given software + * module id + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleMetadataBySoftwareModuleId(@NotNull Long softwareModuleId, + @NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Filter {@link SoftwareModule}s with given + * {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()} + * search text and {@link SoftwareModule#getType()} that are not marked as + * deleted and sort them by means of given distribution set related modules + * on top of the list. + * + * After that the modules are sorted by {@link SoftwareModule#getName()} and + * {@link SoftwareModule#getVersion()} in ascending order. + * + * @param pageable + * page parameter + * @param orderByDistributionId + * the ID of distribution set to be ordered on top + * @param searchText + * filtered as "like" on {@link SoftwareModule#getName()} + * @param type + * filtered as "equal" on {@link SoftwareModule#getType()} + * @return the page of found {@link SoftwareModule} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + @NotNull Pageable pageable, @NotNull Long orderByDistributionId, String searchText, + SoftwareModuleType type); + + /** + * Retrieves all software modules. Deleted ones are filtered. + * + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesAll(@NotNull Pageable pageable); + + /** + * Retrieves all software modules with a given list of ids + * {@link SoftwareModule#getId()}. + * + * @param ids + * to search for + * @return {@link List} of found {@link SoftwareModule}s + */ + List findSoftwareModulesById(@NotEmpty Collection ids); + + /** + * Retrieves all {@link SoftwareModule}s with a given specification. + * + * @param spec + * the specification to filter the software modules + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModule}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModulesByPredicate(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType} + * . + * + * @param pageable + * page parameters + * @param type + * to be filtered on + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Slice findSoftwareModulesByType(@NotNull Pageable pageable, @NotNull SoftwareModuleType type); + + /** + * + * @param id + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getId()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeById(@NotNull Long id); + + /** + * + * @param key + * to search for + * @return {@link SoftwareModuleType} in the repository with given + * {@link SoftwareModuleType#getKey()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key); + + /** + * + * @param name + * to search for + * @return all {@link SoftwareModuleType}s in the repository with given + * {@link SoftwareModuleType#getName()} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModuleType findSoftwareModuleTypeByName(@NotNull String name); + + /** + * @param pageable + * parameter + * @return all {@link SoftwareModuleType}s in the repository. + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull Pageable pageable); + + /** + * Retrieves all {@link SoftwareModuleType}s with a given specification. + * + * @param spec + * the specification to filter the software modules types + * @param pageable + * pagination parameter + * @return the found {@link SoftwareModuleType}s + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + Page findSoftwareModuleTypesAll(@NotNull String rsqlParam, @NotNull Pageable pageable); + + /** + * Retrieves software module including details ( + * {@link SoftwareModule#getArtifacts()}). + * + * @param id + * parameter + * @param isDeleted + * parameter + * @return the found {@link SoftwareModule}s + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + SoftwareModule findSoftwareModuleWithDetails(@NotNull Long id); + + /** + * Updates existing {@link SoftwareModule}. Update-able values are + * {@link SoftwareModule#getDescription()} + * {@link SoftwareModule#getVendor()}. + * + * @param sm + * to update + * + * @return the saved {@link Entity}. + * + * @throws NullPointerException + * of {@link SoftwareModule#getId()} is null + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModule updateSoftwareModule(@NotNull SoftwareModule sm); + + /** + * updates a distribution set meta data value if corresponding entry exists. + * + * @param metadata + * the meta data entry to be updated + * @return the updated meta data entry + * @throws EntityNotFoundException + * in case the meta data entry does not exists and cannot be + * updated + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleMetadata updateSoftwareModuleMetadata(@NotNull SoftwareModuleMetadata metadata); + + /** + * Updates existing {@link SoftwareModuleType}. Update-able value is + * {@link SoftwareModuleType#getDescription()} and + * {@link SoftwareModuleType#getColour()}. + * + * @param sm + * to update + * @return updated {@link Entity} + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY) + SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm); + + /** + * finds all meta data by the given software module id. + * + * @param softwareModuleId + * the software module id to retrieve the meta data from + + * + * @throws RSQLParameterUnsupportedFieldException + * if a field in the RSQL string is used but not provided by the + * given {@code fieldNameProvider} + * @throws RSQLParameterSyntaxException + * if the RSQL syntax is wrong + * @return result of all meta data entries for a given software + * module id + */ + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + List findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId); + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index afe1a1e02..31b222051 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -1,672 +1,672 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.repository.jpa; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.persistence.EntityManager; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.ListJoin; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; - -import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; -import org.eclipse.hawkbit.repository.ArtifactManagement; -import org.eclipse.hawkbit.repository.SoftwareManagement; -import org.eclipse.hawkbit.repository.SoftwareModuleFields; -import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; -import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; -import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; -import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; -import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; -import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; -import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; -import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; -import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; -import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; -import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.LocalArtifact; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.data.domain.SliceImpl; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.transaction.annotation.Isolation; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.validation.annotation.Validated; - -import com.google.common.base.Strings; -import com.google.common.collect.Sets; - -/** - * JPA implementation of {@link SoftwareManagement}. - * - */ -@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) -@Validated -public class JpaSoftwareManagement implements SoftwareManagement { - - @Autowired - private EntityManager entityManager; - - @Autowired - private DistributionSetRepository distributionSetRepository; - - @Autowired - private DistributionSetTypeRepository distributionSetTypeRepository; - - @Autowired - private SoftwareModuleRepository softwareModuleRepository; - - @Autowired - private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; - - @Autowired - private SoftwareModuleTypeRepository softwareModuleTypeRepository; - - @Autowired - private NoCountPagingRepository criteriaNoCountDao; - - @Autowired - private AuditorAware auditorProvider; - - @Autowired - private ArtifactManagement artifactManagement; - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModule updateSoftwareModule(final SoftwareModule sm) { - checkNotNull(sm.getId()); - - final JpaSoftwareModule module = softwareModuleRepository.findOne(sm.getId()); - - boolean updated = false; - if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { - module.setDescription(sm.getDescription()); - updated = true; - } - if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { - module.setVendor(sm.getVendor()); - updated = true; - } - - return updated ? softwareModuleRepository.save(module) : module; - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModuleType updateSoftwareModuleType(final SoftwareModuleType sm) { - checkNotNull(sm.getId()); - - final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); - - boolean updated = false; - if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) { - type.setDescription(sm.getDescription()); - updated = true; - } - if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { - type.setColour(sm.getColour()); - updated = true; - } - return updated ? softwareModuleTypeRepository.save(type) : type; - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModule createSoftwareModule(final SoftwareModule swModule) { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - return softwareModuleRepository.save((JpaSoftwareModule) swModule); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public List createSoftwareModule(final Collection swModules) { - swModules.forEach(swModule -> { - if (null != swModule.getId()) { - throw new EntityAlreadyExistsException(); - } - }); - - @SuppressWarnings({ "unchecked", "rawtypes" }) - final Collection jpaCast = (Collection) swModules; - - return new ArrayList<>(softwareModuleRepository.save(jpaCast)); - } - - @Override - public Slice findSoftwareModulesByType(final Pageable pageable, final SoftwareModuleType type) { - - final List> specList = new LinkedList<>(); - - Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - private static Slice convertSmPage(final Slice findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); - } - - private static Page convertSmPage(final Page findAll, final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - private static Page convertSmMdPage(final Page findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - @Override - public Long countSoftwareModulesByType(final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - - spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public SoftwareModule findSoftwareModuleById(final Long id) { - return artifactManagement.findSoftwareModuleById(id); - } - - @Override - public SoftwareModule findSoftwareModuleByNameAndVersion(final String name, final String version, - final SoftwareModuleType type) { - - return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, (JpaSoftwareModuleType) type); - } - - private boolean isUnassigned(final JpaSoftwareModule bsmMerged) { - return distributionSetRepository.findByModules(bsmMerged).isEmpty(); - } - - private Slice findSwModuleByCriteriaAPI(final Pageable pageable, - final List> specList) { - return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, - JpaSoftwareModule.class); - } - - private Long countSwModuleByCriteriaAPI(final List> specList) { - return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); - } - - private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) { - for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { - artifactManagement.deleteLocalArtifact(localArtifact); - } - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModules(final Collection ids) { - final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); - final Set assignedModuleIds = new HashSet<>(); - swModulesToDelete.forEach(swModule -> { - - // delete binary data of artifacts - deleteGridFsArtifacts(swModule); - - if (isUnassigned(swModule)) { - - softwareModuleRepository.delete(swModule); - - } else { - - assignedModuleIds.add(swModule.getId()); - } - }); - - if (!assignedModuleIds.isEmpty()) { - String currentUser = null; - if (auditorProvider != null) { - currentUser = auditorProvider.getCurrentAuditor(); - } - softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, - assignedModuleIds.toArray(new Long[0])); - } - } - - @Override - public Slice findSoftwareModulesAll(final Pageable pageable) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(JpaSoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - @Override - public Long countSoftwareModulesAll() { - - final List> specList = new ArrayList<>(); - - final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public SoftwareModule findSoftwareModuleWithDetails(final Long id) { - return artifactManagement.findSoftwareModuleWithDetails(id); - } - - @Override - public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); - - return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); - } - - @Override - public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { - - final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); - - return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); - } - - private static Page convertSmTPage(final Page findAll, - final Pageable pageable) { - return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); - } - - @Override - @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) - public List findSoftwareModulesById(final Collection ids) { - return new ArrayList<>(softwareModuleRepository.findByIdIn(ids)); - } - - @Override - public Slice findSoftwareModuleByFilters(final Pageable pageable, final String searchText, - final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - } - - spec = (root, query, cb) -> { - if (!query.getResultType().isAssignableFrom(Long.class)) { - root.fetch(JpaSoftwareModule_.type); - } - return cb.conjunction(); - }; - - specList.add(spec); - - return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); - } - - @Override - public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( - final Pageable pageable, final Long orderByDistributionId, final String searchText, - final SoftwareModuleType ty) { - final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; - - final List resultList = new ArrayList<>(); - final int pageSize = pageable.getPageSize(); - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - - // get the assigned software modules - final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); - final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); - assignedQuery.distinct(true); - final ListJoin assignedDsJoin = assignedRoot - .join(JpaSoftwareModule_.assignedTo); - // build the specifications and then to predicates necessary by the - // given filters - final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), - assignedRoot, assignedQuery, cb, - cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId)); - // if we have some predicates then add it to the where clause of the - // multi select - assignedQuery.where(specPredicate); - assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)), - cb.asc(assignedRoot.get(JpaSoftwareModule_.version))); - // don't page the assigned query on database, we need all assigned - // software modules to filter - // them out in the unassigned query - final List assignedSoftwareModules = entityManager.createQuery(assignedQuery) - .getResultList(); - // map result - if (pageable.getOffset() < assignedSoftwareModules.size()) { - assignedSoftwareModules - .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) - .forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true))); - } - - if (assignedSoftwareModules.size() >= pageSize) { - return new SliceImpl<>(resultList); - } - - // get the unassigned software modules - final CriteriaQuery unassignedQuery = cb.createQuery(JpaSoftwareModule.class); - unassignedQuery.distinct(true); - final Root unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class); - - Predicate[] unassignedSpec; - if (!assignedSoftwareModules.isEmpty()) { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id) - .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); - } else { - unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, - unassignedQuery, cb); - } - - unassignedQuery.where(unassignedSpec); - unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)), - cb.asc(unassignedRoot.get(JpaSoftwareModule_.version))); - final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) - .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) - .setMaxResults(pageSize).getResultList(); - // map result - unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false))); - - return new SliceImpl<>(resultList); - } - - private static List> buildSpecificationList(final String searchText, - final JpaSoftwareModuleType type) { - final List> specList = new ArrayList<>(); - if (!Strings.isNullOrEmpty(searchText)) { - specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); - } - if (type != null) { - specList.add(SoftwareModuleSpecification.equalType(type)); - } - specList.add(SoftwareModuleSpecification.isDeletedFalse()); - return specList; - } - - private Predicate[] specificationsToPredicate(final List> specifications, - final Root root, final CriteriaQuery query, final CriteriaBuilder cb, - final Predicate... additionalPredicates) { - final List predicates = new ArrayList<>(); - specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); - for (final Predicate predicate : additionalPredicates) { - predicates.add(predicate); - } - return predicates.toArray(new Predicate[predicates.size()]); - } - - @Override - public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { - - final List> specList = new ArrayList<>(); - - Specification spec = SoftwareModuleSpecification.isDeletedFalse(); - specList.add(spec); - - if (!Strings.isNullOrEmpty(searchText)) { - spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); - specList.add(spec); - } - - if (null != type) { - spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); - specList.add(spec); - } - - return countSwModuleByCriteriaAPI(specList); - } - - @Override - public Page findSoftwareModuleTypesAll(final Pageable pageable) { - return softwareModuleTypeRepository.findByDeleted(pageable, false); - } - - @Override - public Long countSoftwareModuleTypesAll() { - return softwareModuleTypeRepository.countByDeleted(false); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeByKey(final String key) { - return softwareModuleTypeRepository.findByKey(key); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeById(final Long id) { - return softwareModuleTypeRepository.findOne(id); - } - - @Override - public SoftwareModuleType findSoftwareModuleTypeByName(final String name) { - return softwareModuleTypeRepository.findByName(name); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public SoftwareModuleType createSoftwareModuleType(final SoftwareModuleType type) { - if (type.getId() != null) { - throw new EntityAlreadyExistsException("Given type contains an Id!"); - } - - return softwareModuleTypeRepository.save((JpaSoftwareModuleType) type); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModuleType(final SoftwareModuleType ty) { - final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; - - if (softwareModuleRepository.countByType(type) > 0 - || distributionSetTypeRepository.countByElementsSmType(type) > 0) { - final JpaSoftwareModuleType toDelete = entityManager.merge(type); - toDelete.setDeleted(true); - softwareModuleTypeRepository.save(toDelete); - } else { - softwareModuleTypeRepository.delete(type.getId()); - } - } - - @Override - public Page findSoftwareModuleByAssignedTo(final Pageable pageable, final DistributionSet set) { - return softwareModuleRepository.findByAssignedTo(pageable, (JpaDistributionSet) set); - } - - @Override - public Page findSoftwareModuleByAssignedToAndType(final Pageable pageable, - final DistributionSet set, final SoftwareModuleType type) { - return softwareModuleRepository.findByAssignedToAndType(pageable, (JpaDistributionSet) set, - (JpaSoftwareModuleType) type); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public SoftwareModuleMetadata createSoftwareModuleMetadata(final SoftwareModuleMetadata md) { - final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; - - if (softwareModuleMetadataRepository.exists(metadata.getId())) { - throwMetadataKeyAlreadyExists(metadata.getId().getKey()); - } - // merge base software module so optLockRevision gets updated and audit - // log written because - // modifying metadata is modifying the base software module itself for - // auditing purposes. - entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public List createSoftwareModuleMetadata(final Collection md) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - final Collection metadata = (Collection) md; - - for (final JpaSoftwareModuleMetadata softwareModuleMetadata : metadata) { - checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); - } - metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L)); - return new ArrayList<>(softwareModuleMetadataRepository.save(metadata)); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public SoftwareModuleMetadata updateSoftwareModuleMetadata(final SoftwareModuleMetadata md) { - final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; - - // check if exists otherwise throw entity not found exception - findSoftwareModuleMetadata(metadata.getId()); - // touch it to update the lock revision because we are modifying the - // software module - // indirectly - entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); - return softwareModuleMetadataRepository.save(metadata); - } - - @Override - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - @Modifying - public void deleteSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { - softwareModuleMetadataRepository.delete(new SwMetadataCompositeKey(softwareModule, key)); - } - - @Override - public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long swId, - final Pageable pageable) { - return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); - } - - @Override - public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, - final String rsqlParam, final Pageable pageable) { - - final Specification spec = RSQLUtility.parse(rsqlParam, - SoftwareModuleMetadataFields.class); - return convertSmMdPage( - softwareModuleMetadataRepository - .findAll( - (Specification) (root, query, cb) -> cb.and( - cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) - .get(JpaSoftwareModule_.id), softwareModuleId), - spec.toPredicate(root, query, cb)), - pageable), - pageable); - } - - @Override - public List findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) { - return new ArrayList<> ( softwareModuleMetadataRepository - .findAll( - (Specification) (root, query, cb) -> cb.and( - cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) - .get(JpaSoftwareModule_.id), softwareModuleId)))); - } - - @Override - public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { - return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); - } - - private SoftwareModuleMetadata findSoftwareModuleMetadata(final SwMetadataCompositeKey id) { - final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); - if (findOne == null) { - throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); - } - return findOne; - } - - private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { - if (softwareModuleMetadataRepository.exists(metadataId)) { - throw new EntityAlreadyExistsException( - "Metadata entry with key '" + metadataId.getKey() + "' already exists"); - } - } - - private static void throwMetadataKeyAlreadyExists(final String metadataKey) { - throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public void deleteSoftwareModule(final SoftwareModule bsm) { - deleteSoftwareModules(Sets.newHashSet(bsm.getId())); - } - - @Override - @Modifying - @Transactional(isolation = Isolation.READ_UNCOMMITTED) - public List createSoftwareModuleType(final Collection types) { - - return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); - } - -} +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; +import org.eclipse.hawkbit.repository.ArtifactManagement; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.SoftwareModuleFields; +import org.eclipse.hawkbit.repository.SoftwareModuleMetadataFields; +import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields; +import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet; +import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType; +import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_; +import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey; +import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility; +import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification; +import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder; +import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.LocalArtifact; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.AuditorAware; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; + +/** + * JPA implementation of {@link SoftwareManagement}. + * + */ +@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) +@Validated +public class JpaSoftwareManagement implements SoftwareManagement { + + @Autowired + private EntityManager entityManager; + + @Autowired + private DistributionSetRepository distributionSetRepository; + + @Autowired + private DistributionSetTypeRepository distributionSetTypeRepository; + + @Autowired + private SoftwareModuleRepository softwareModuleRepository; + + @Autowired + private SoftwareModuleMetadataRepository softwareModuleMetadataRepository; + + @Autowired + private SoftwareModuleTypeRepository softwareModuleTypeRepository; + + @Autowired + private NoCountPagingRepository criteriaNoCountDao; + + @Autowired + private AuditorAware auditorProvider; + + @Autowired + private ArtifactManagement artifactManagement; + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule updateSoftwareModule(final SoftwareModule sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModule module = softwareModuleRepository.findOne(sm.getId()); + + boolean updated = false; + if (null == sm.getDescription() || !sm.getDescription().equals(module.getDescription())) { + module.setDescription(sm.getDescription()); + updated = true; + } + if (null == sm.getVendor() || !sm.getVendor().equals(module.getVendor())) { + module.setVendor(sm.getVendor()); + updated = true; + } + + return updated ? softwareModuleRepository.save(module) : module; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType updateSoftwareModuleType(final SoftwareModuleType sm) { + checkNotNull(sm.getId()); + + final JpaSoftwareModuleType type = softwareModuleTypeRepository.findOne(sm.getId()); + + boolean updated = false; + if (sm.getDescription() == null || !sm.getDescription().equals(type.getDescription())) { + type.setDescription(sm.getDescription()); + updated = true; + } + if (sm.getColour() != null && !sm.getColour().equals(type.getColour())) { + type.setColour(sm.getColour()); + updated = true; + } + return updated ? softwareModuleTypeRepository.save(type) : type; + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModule createSoftwareModule(final SoftwareModule swModule) { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + return softwareModuleRepository.save((JpaSoftwareModule) swModule); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModule(final Collection swModules) { + swModules.forEach(swModule -> { + if (null != swModule.getId()) { + throw new EntityAlreadyExistsException(); + } + }); + + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection jpaCast = (Collection) swModules; + + return new ArrayList<>(softwareModuleRepository.save(jpaCast)); + } + + @Override + public Slice findSoftwareModulesByType(final Pageable pageable, final SoftwareModuleType type) { + + final List> specList = new LinkedList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + private static Slice convertSmPage(final Slice findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0); + } + + private static Page convertSmPage(final Page findAll, final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + private static Page convertSmMdPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + public Long countSoftwareModulesByType(final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + + spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleById(final Long id) { + return artifactManagement.findSoftwareModuleById(id); + } + + @Override + public SoftwareModule findSoftwareModuleByNameAndVersion(final String name, final String version, + final SoftwareModuleType type) { + + return softwareModuleRepository.findOneByNameAndVersionAndType(name, version, (JpaSoftwareModuleType) type); + } + + private boolean isUnassigned(final JpaSoftwareModule bsmMerged) { + return distributionSetRepository.findByModules(bsmMerged).isEmpty(); + } + + private Slice findSwModuleByCriteriaAPI(final Pageable pageable, + final List> specList) { + return criteriaNoCountDao.findAll(SpecificationsBuilder.combineWithAnd(specList), pageable, + JpaSoftwareModule.class); + } + + private Long countSwModuleByCriteriaAPI(final List> specList) { + return softwareModuleRepository.count(SpecificationsBuilder.combineWithAnd(specList)); + } + + private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) { + for (final LocalArtifact localArtifact : swModule.getLocalArtifacts()) { + artifactManagement.deleteLocalArtifact(localArtifact); + } + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModules(final Collection ids) { + final List swModulesToDelete = softwareModuleRepository.findByIdIn(ids); + final Set assignedModuleIds = new HashSet<>(); + swModulesToDelete.forEach(swModule -> { + + // delete binary data of artifacts + deleteGridFsArtifacts(swModule); + + if (isUnassigned(swModule)) { + + softwareModuleRepository.delete(swModule); + + } else { + + assignedModuleIds.add(swModule.getId()); + } + }); + + if (!assignedModuleIds.isEmpty()) { + String currentUser = null; + if (auditorProvider != null) { + currentUser = auditorProvider.getCurrentAuditor(); + } + softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser, + assignedModuleIds.toArray(new Long[0])); + } + } + + @Override + public Slice findSoftwareModulesAll(final Pageable pageable) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Long countSoftwareModulesAll() { + + final List> specList = new ArrayList<>(); + + final Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public SoftwareModule findSoftwareModuleWithDetails(final Long id) { + return artifactManagement.findSoftwareModuleWithDetails(id); + } + + @Override + public Page findSoftwareModulesByPredicate(final String rsqlParam, final Pageable pageable) { + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleFields.class); + + return convertSmPage(softwareModuleRepository.findAll(spec, pageable), pageable); + } + + @Override + public Page findSoftwareModuleTypesAll(final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, SoftwareModuleTypeFields.class); + + return convertSmTPage(softwareModuleTypeRepository.findAll(spec, pageable), pageable); + } + + private static Page convertSmTPage(final Page findAll, + final Pageable pageable) { + return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements()); + } + + @Override + @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) + public List findSoftwareModulesById(final Collection ids) { + return new ArrayList<>(softwareModuleRepository.findByIdIn(ids)); + } + + @Override + public Slice findSoftwareModuleByFilters(final Pageable pageable, final String searchText, + final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + spec = (root, query, cb) -> { + if (!query.getResultType().isAssignableFrom(Long.class)) { + root.fetch(JpaSoftwareModule_.type); + } + return cb.conjunction(); + }; + + specList.add(spec); + + return convertSmPage(findSwModuleByCriteriaAPI(pageable, specList), pageable); + } + + @Override + public Slice findSoftwareModuleOrderBySetAssignmentAndModuleNameAscModuleVersionAsc( + final Pageable pageable, final Long orderByDistributionId, final String searchText, + final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + final List resultList = new ArrayList<>(); + final int pageSize = pageable.getPageSize(); + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + + // get the assigned software modules + final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); + final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); + assignedQuery.distinct(true); + final ListJoin assignedDsJoin = assignedRoot + .join(JpaSoftwareModule_.assignedTo); + // build the specifications and then to predicates necessary by the + // given filters + final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, type), + assignedRoot, assignedQuery, cb, + cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId)); + // if we have some predicates then add it to the where clause of the + // multi select + assignedQuery.where(specPredicate); + assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(assignedRoot.get(JpaSoftwareModule_.version))); + // don't page the assigned query on database, we need all assigned + // software modules to filter + // them out in the unassigned query + final List assignedSoftwareModules = entityManager.createQuery(assignedQuery) + .getResultList(); + // map result + if (pageable.getOffset() < assignedSoftwareModules.size()) { + assignedSoftwareModules + .subList(pageable.getOffset(), Math.min(assignedSoftwareModules.size(), pageable.getPageSize())) + .forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true))); + } + + if (assignedSoftwareModules.size() >= pageSize) { + return new SliceImpl<>(resultList); + } + + // get the unassigned software modules + final CriteriaQuery unassignedQuery = cb.createQuery(JpaSoftwareModule.class); + unassignedQuery.distinct(true); + final Root unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class); + + Predicate[] unassignedSpec; + if (!assignedSoftwareModules.isEmpty()) { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id) + .in(assignedSoftwareModules.stream().map(sw -> sw.getId()).collect(Collectors.toList())))); + } else { + unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, type), unassignedRoot, + unassignedQuery, cb); + } + + unassignedQuery.where(unassignedSpec); + unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)), + cb.asc(unassignedRoot.get(JpaSoftwareModule_.version))); + final List unassignedSoftwareModules = entityManager.createQuery(unassignedQuery) + .setFirstResult(Math.max(0, pageable.getOffset() - assignedSoftwareModules.size())) + .setMaxResults(pageSize).getResultList(); + // map result + unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false))); + + return new SliceImpl<>(resultList); + } + + private static List> buildSpecificationList(final String searchText, + final JpaSoftwareModuleType type) { + final List> specList = new ArrayList<>(); + if (!Strings.isNullOrEmpty(searchText)) { + specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText)); + } + if (type != null) { + specList.add(SoftwareModuleSpecification.equalType(type)); + } + specList.add(SoftwareModuleSpecification.isDeletedFalse()); + return specList; + } + + private Predicate[] specificationsToPredicate(final List> specifications, + final Root root, final CriteriaQuery query, final CriteriaBuilder cb, + final Predicate... additionalPredicates) { + final List predicates = new ArrayList<>(); + specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb))); + for (final Predicate predicate : additionalPredicates) { + predicates.add(predicate); + } + return predicates.toArray(new Predicate[predicates.size()]); + } + + @Override + public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) { + + final List> specList = new ArrayList<>(); + + Specification spec = SoftwareModuleSpecification.isDeletedFalse(); + specList.add(spec); + + if (!Strings.isNullOrEmpty(searchText)) { + spec = SoftwareModuleSpecification.likeNameOrVersion(searchText); + specList.add(spec); + } + + if (null != type) { + spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type); + specList.add(spec); + } + + return countSwModuleByCriteriaAPI(specList); + } + + @Override + public Page findSoftwareModuleTypesAll(final Pageable pageable) { + return softwareModuleTypeRepository.findByDeleted(pageable, false); + } + + @Override + public Long countSoftwareModuleTypesAll() { + return softwareModuleTypeRepository.countByDeleted(false); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByKey(final String key) { + return softwareModuleTypeRepository.findByKey(key); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeById(final Long id) { + return softwareModuleTypeRepository.findOne(id); + } + + @Override + public SoftwareModuleType findSoftwareModuleTypeByName(final String name) { + return softwareModuleTypeRepository.findByName(name); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public SoftwareModuleType createSoftwareModuleType(final SoftwareModuleType type) { + if (type.getId() != null) { + throw new EntityAlreadyExistsException("Given type contains an Id!"); + } + + return softwareModuleTypeRepository.save((JpaSoftwareModuleType) type); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModuleType(final SoftwareModuleType ty) { + final JpaSoftwareModuleType type = (JpaSoftwareModuleType) ty; + + if (softwareModuleRepository.countByType(type) > 0 + || distributionSetTypeRepository.countByElementsSmType(type) > 0) { + final JpaSoftwareModuleType toDelete = entityManager.merge(type); + toDelete.setDeleted(true); + softwareModuleTypeRepository.save(toDelete); + } else { + softwareModuleTypeRepository.delete(type.getId()); + } + } + + @Override + public Page findSoftwareModuleByAssignedTo(final Pageable pageable, final DistributionSet set) { + return softwareModuleRepository.findByAssignedTo(pageable, (JpaDistributionSet) set); + } + + @Override + public Page findSoftwareModuleByAssignedToAndType(final Pageable pageable, + final DistributionSet set, final SoftwareModuleType type) { + return softwareModuleRepository.findByAssignedToAndType(pageable, (JpaDistributionSet) set, + (JpaSoftwareModuleType) type); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata createSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + if (softwareModuleMetadataRepository.exists(metadata.getId())) { + throwMetadataKeyAlreadyExists(metadata.getId().getKey()); + } + // merge base software module so optLockRevision gets updated and audit + // log written because + // modifying metadata is modifying the base software module itself for + // auditing purposes. + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public List createSoftwareModuleMetadata(final Collection md) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final Collection metadata = (Collection) md; + + for (final JpaSoftwareModuleMetadata softwareModuleMetadata : metadata) { + checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId()); + } + metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L)); + return new ArrayList<>(softwareModuleMetadataRepository.save(metadata)); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public SoftwareModuleMetadata updateSoftwareModuleMetadata(final SoftwareModuleMetadata md) { + final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) md; + + // check if exists otherwise throw entity not found exception + findSoftwareModuleMetadata(metadata.getId()); + // touch it to update the lock revision because we are modifying the + // software module + // indirectly + entityManager.merge((JpaSoftwareModule) metadata.getSoftwareModule()).setLastModifiedAt(-1L); + return softwareModuleMetadataRepository.save(metadata); + } + + @Override + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + @Modifying + public void deleteSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + softwareModuleMetadataRepository.delete(new SwMetadataCompositeKey(softwareModule, key)); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long swId, + final Pageable pageable) { + return softwareModuleMetadataRepository.findBySoftwareModuleId(swId, pageable); + } + + @Override + public Page findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId, + final String rsqlParam, final Pageable pageable) { + + final Specification spec = RSQLUtility.parse(rsqlParam, + SoftwareModuleMetadataFields.class); + return convertSmMdPage( + softwareModuleMetadataRepository + .findAll( + (Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) + .get(JpaSoftwareModule_.id), softwareModuleId), + spec.toPredicate(root, query, cb)), + pageable), + pageable); + } + + @Override + public List findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) { + return new ArrayList<> ( softwareModuleMetadataRepository + .findAll( + (Specification) (root, query, cb) -> cb.and( + cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) + .get(JpaSoftwareModule_.id), softwareModuleId)))); + } + + @Override + public SoftwareModuleMetadata findSoftwareModuleMetadata(final SoftwareModule softwareModule, final String key) { + return findSoftwareModuleMetadata(new SwMetadataCompositeKey(softwareModule, key)); + } + + private SoftwareModuleMetadata findSoftwareModuleMetadata(final SwMetadataCompositeKey id) { + final SoftwareModuleMetadata findOne = softwareModuleMetadataRepository.findOne(id); + if (findOne == null) { + throw new EntityNotFoundException("Metadata with key '" + id.getKey() + "' does not exist"); + } + return findOne; + } + + private void checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(final SwMetadataCompositeKey metadataId) { + if (softwareModuleMetadataRepository.exists(metadataId)) { + throw new EntityAlreadyExistsException( + "Metadata entry with key '" + metadataId.getKey() + "' already exists"); + } + } + + private static void throwMetadataKeyAlreadyExists(final String metadataKey) { + throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists"); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public void deleteSoftwareModule(final SoftwareModule bsm) { + deleteSoftwareModules(Sets.newHashSet(bsm.getId())); + } + + @Override + @Modifying + @Transactional(isolation = Isolation.READ_UNCOMMITTED) + public List createSoftwareModuleType(final Collection types) { + + return types.stream().map(this::createSoftwareModuleType).collect(Collectors.toList()); + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index fc879aa87..5bda8f63b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -1,199 +1,199 @@ -/** - * 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.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.NamedEntityGraphs; -import javax.persistence.NamedSubgraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -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.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.persistence.annotations.CascadeOnDelete; -import org.eclipse.persistence.descriptors.DescriptorEvent; - -/** - * JPA implementation of {@link Action}. - */ -@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), - @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), - @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) -@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), - @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), - @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) -@Entity -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action,EventAwareEntity { - private static final long serialVersionUID = 1L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) - private JpaDistributionSet distributionSet; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) - private JpaTarget target; - - @Column(name = "active") - private boolean active; - - @Column(name = "action_type", nullable = false) - @Enumerated(EnumType.STRING) - private ActionType actionType; - - @Column(name = "forced_time") - private long forcedTime; - - @Column(name = "status") - private Status status; - - @CascadeOnDelete - @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { - CascadeType.REMOVE }) - private List actionStatus; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) - private JpaRolloutGroup rolloutGroup; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) - private JpaRollout rollout; - - @Override - public DistributionSet getDistributionSet() { - return distributionSet; - } - - @Override - public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = (JpaDistributionSet) distributionSet; - } - - public void setActive(final boolean active) { - this.active = active; - } - - @Override - public Status getStatus() { - return status; - } - - @Override - public void setStatus(final Status status) { - this.status = status; - } - - @Override - public boolean isActive() { - return active; - } - - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - @Override - public ActionType getActionType() { - return actionType; - } - - @Override - public List getActionStatus() { - return actionStatus; - } - - @Override - public void setTarget(final Target target) { - this.target = (JpaTarget) target; - } - - @Override - public Target getTarget() { - return target; - } - - @Override - public long getForcedTime() { - return forcedTime; - } - - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - - @Override - public RolloutGroup getRolloutGroup() { - return rolloutGroup; - } - - public void setRolloutGroup(final RolloutGroup rolloutGroup) { - this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; - } - - @Override - public Rollout getRollout() { - return rollout; - } - - public void setRollout(final Rollout rollout) { - this.rollout = (JpaRollout) rollout; - } - - @Override - public String toString() { - return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; - } - - @Override - public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); - - } - - @Override - public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus(). - post(new ActionPropertyChangeEvent(jpaAction, EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); - - } - - - @Override - public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - - } - -} +/** + * 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.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.NamedEntityGraphs; +import javax.persistence.NamedSubgraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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.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.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA implementation of {@link Action}. + */ +@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"), + @Index(name = "sp_idx_action_02", columnList = "tenant,target,active"), + @Index(name = "sp_idx_action_prim", columnList = "tenant,id") }) +@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }), + @NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"), + @NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) }) +@Entity +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action,EventAwareEntity { + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds")) + private JpaDistributionSet distributionSet; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target")) + private JpaTarget target; + + @Column(name = "active") + private boolean active; + + @Column(name = "action_type", nullable = false) + @Enumerated(EnumType.STRING) + private ActionType actionType; + + @Column(name = "forced_time") + private long forcedTime; + + @Column(name = "status") + private Status status; + + @CascadeOnDelete + @OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = { + CascadeType.REMOVE }) + private List actionStatus; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup")) + private JpaRolloutGroup rolloutGroup; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout")) + private JpaRollout rollout; + + @Override + public DistributionSet getDistributionSet() { + return distributionSet; + } + + @Override + public void setDistributionSet(final DistributionSet distributionSet) { + this.distributionSet = (JpaDistributionSet) distributionSet; + } + + public void setActive(final boolean active) { + this.active = active; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public void setStatus(final Status status) { + this.status = status; + } + + @Override + public boolean isActive() { + return active; + } + + public void setActionType(final ActionType actionType) { + this.actionType = actionType; + } + + @Override + public ActionType getActionType() { + return actionType; + } + + @Override + public List getActionStatus() { + return actionStatus; + } + + @Override + public void setTarget(final Target target) { + this.target = (JpaTarget) target; + } + + @Override + public Target getTarget() { + return target; + } + + @Override + public long getForcedTime() { + return forcedTime; + } + + public void setForcedTime(final long forcedTime) { + this.forcedTime = forcedTime; + } + + @Override + public RolloutGroup getRolloutGroup() { + return rolloutGroup; + } + + public void setRolloutGroup(final RolloutGroup rolloutGroup) { + this.rolloutGroup = (JpaRolloutGroup) rolloutGroup; + } + + @Override + public Rollout getRollout() { + return rollout; + } + + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public String toString() { + return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); + + } + + @Override + public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus(). + post(new ActionPropertyChangeEvent(jpaAction, EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); + + } + + + @Override + public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index af8984286..77a5f88fd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -1,320 +1,320 @@ -/** - * 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.util.ArrayList; -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 javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; - -import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; -import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; -import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; -import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; -import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -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; -import org.eclipse.hawkbit.repository.model.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.repository.model.SoftwareModule; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.persistence.annotations.CascadeOnDelete; -import org.eclipse.persistence.descriptors.DescriptorEvent; - -/** - * Jpa implementation of {@link DistributionSet}. - * - */ -@Entity -@Table(name = "sp_distribution_set", uniqueConstraints = { - @UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = { - @Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"), - @Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"), - @Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") }) -@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"), - @NamedAttributeNode("tags"), @NamedAttributeNode("type") }) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet,EventAwareEntity { - private static final long serialVersionUID = 1L; - - private static final String COMPLETE = "complete"; - - @Column(name = "required_migration_step") - private boolean requiredMigrationStep; - - @ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) - @JoinTable(name = "sp_ds_module", joinColumns = { - @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = { - @JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) }) - private final Set modules = new HashSet<>(); - - @ManyToMany(targetEntity = JpaDistributionSetTag.class) - @JoinTable(name = "sp_ds_dstag", joinColumns = { - @JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = { - @JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) }) - private Set tags = new HashSet<>(); - - @Column(name = "deleted") - private boolean deleted; - - @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) - private List assignedToTargets; - - @OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY) - private List installedAtTargets; - - @OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY) - private List actions; - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = { - CascadeType.REMOVE }) - @JoinColumn(name = "ds_id", insertable = false, updatable = false) - private final List metadata = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class) - @JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds")) - private DistributionSetType type; - - @Column(name = "complete") - private boolean complete; - - /** - * Default constructor. - */ - public JpaDistributionSet() { - super(); - } - - /** - * Parameterized constructor. - * - * @param name - * of the {@link DistributionSet} - * @param version - * of the {@link DistributionSet} - * @param description - * of the {@link DistributionSet} - * @param type - * of the {@link DistributionSet} - * @param moduleList - * {@link SoftwareModule}s of the {@link DistributionSet} - */ - public JpaDistributionSet(final String name, final String version, final String description, - final DistributionSetType type, final Collection moduleList) { - super(name, version, description); - - this.type = type; - if (moduleList != null) { - moduleList.forEach(this::addModule); - } - if (this.type != null) { - complete = this.type.checkComplete(this); - } - } - - @Override - public Set getTags() { - return tags; - } - - @Override - public boolean isDeleted() { - return deleted; - } - - @Override - public List getMetadata() { - return Collections.unmodifiableList(metadata); - } - - public List getActions() { - return actions; - } - - @Override - public boolean isRequiredMigrationStep() { - return requiredMigrationStep; - } - - @Override - public DistributionSet setDeleted(final boolean deleted) { - this.deleted = deleted; - return this; - } - - @Override - public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) { - requiredMigrationStep = isRequiredMigrationStep; - return this; - } - - public DistributionSet setTags(final Set tags) { - this.tags = tags; - return this; - } - - @Override - public List getAssignedTargets() { - return assignedToTargets; - } - - @Override - public List getInstalledTargets() { - return installedAtTargets; - } - - @Override - public String toString() { - return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision() - + ", getId()=" + getId() + "]"; - } - - @Override - public Set getModules() { - return Collections.unmodifiableSet(modules); - } - - @Override - public boolean addModule(final SoftwareModule softwareModule) { - - // we cannot allow that modules are added without a type defined - if (type == null) { - throw new DistributionSetTypeUndefinedException(); - } - - // check if it is allowed to such a module to this DS type - if (!type.containsModuleType(softwareModule.getType())) { - throw new UnsupportedSoftwareModuleForThisDistributionSetException(); - } - - final Optional found = modules.stream() - .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); - - if (found.isPresent()) { - return false; - } - - final long allready = modules.stream() - .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count(); - - if (allready >= softwareModule.getType().getMaxAssignments()) { - final Optional sameKey = modules.stream() - .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst(); - modules.remove(sameKey.get()); - } - - if (modules.add(softwareModule)) { - complete = type.checkComplete(this); - return true; - } - - return false; - } - - @Override - public boolean removeModule(final SoftwareModule softwareModule) { - final Optional found = modules.stream() - .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); - - if (found.isPresent()) { - modules.remove(found.get()); - complete = type.checkComplete(this); - return true; - } - - return false; - - } - - @Override - public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) { - final Optional result = modules.stream().filter(module -> module.getType().equals(type)) - .findFirst(); - - if (result.isPresent()) { - return result.get(); - } - - return null; - } - - @Override - public DistributionSetType getType() { - return type; - } - - @Override - public void setType(final DistributionSetType type) { - this.type = type; - } - - @Override - public boolean isComplete() { - return complete; - } - - @Override - public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); - - } - - @Override - public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - final Map.Values> changeSet = EntityPropertyChangeHelper.getChangeSet( - JpaDistributionSet.class, descriptorEvent); - if (changeSet.containsKey(COMPLETE) - && changeSet.get(COMPLETE).getOldValue().equals(false) - && changeSet.get(COMPLETE).getNewValue().equals(true)) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post( - new DistributionCreatedEvent(jpaDistributionSet))); - } - - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); - - } - - @Override - public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - - } - -} +/** + * 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.util.ArrayList; +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 javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; +import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; +import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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; +import org.eclipse.hawkbit.repository.model.DistributionSetTag; +import org.eclipse.hawkbit.repository.model.DistributionSetType; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleType; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * Jpa implementation of {@link DistributionSet}. + * + */ +@Entity +@Table(name = "sp_distribution_set", uniqueConstraints = { + @UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = { + @Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"), + @Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"), + @Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") }) +@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"), + @NamedAttributeNode("tags"), @NamedAttributeNode("type") }) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet,EventAwareEntity { + private static final long serialVersionUID = 1L; + + private static final String COMPLETE = "complete"; + + @Column(name = "required_migration_step") + private boolean requiredMigrationStep; + + @ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY) + @JoinTable(name = "sp_ds_module", joinColumns = { + @JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = { + @JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) }) + private final Set modules = new HashSet<>(); + + @ManyToMany(targetEntity = JpaDistributionSetTag.class) + @JoinTable(name = "sp_ds_dstag", joinColumns = { + @JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = { + @JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) }) + private Set tags = new HashSet<>(); + + @Column(name = "deleted") + private boolean deleted; + + @OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY) + private List assignedToTargets; + + @OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY) + private List installedAtTargets; + + @OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY) + private List actions; + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = { + CascadeType.REMOVE }) + @JoinColumn(name = "ds_id", insertable = false, updatable = false) + private final List metadata = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class) + @JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds")) + private DistributionSetType type; + + @Column(name = "complete") + private boolean complete; + + /** + * Default constructor. + */ + public JpaDistributionSet() { + super(); + } + + /** + * Parameterized constructor. + * + * @param name + * of the {@link DistributionSet} + * @param version + * of the {@link DistributionSet} + * @param description + * of the {@link DistributionSet} + * @param type + * of the {@link DistributionSet} + * @param moduleList + * {@link SoftwareModule}s of the {@link DistributionSet} + */ + public JpaDistributionSet(final String name, final String version, final String description, + final DistributionSetType type, final Collection moduleList) { + super(name, version, description); + + this.type = type; + if (moduleList != null) { + moduleList.forEach(this::addModule); + } + if (this.type != null) { + complete = this.type.checkComplete(this); + } + } + + @Override + public Set getTags() { + return tags; + } + + @Override + public boolean isDeleted() { + return deleted; + } + + @Override + public List getMetadata() { + return Collections.unmodifiableList(metadata); + } + + public List getActions() { + return actions; + } + + @Override + public boolean isRequiredMigrationStep() { + return requiredMigrationStep; + } + + @Override + public DistributionSet setDeleted(final boolean deleted) { + this.deleted = deleted; + return this; + } + + @Override + public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) { + requiredMigrationStep = isRequiredMigrationStep; + return this; + } + + public DistributionSet setTags(final Set tags) { + this.tags = tags; + return this; + } + + @Override + public List getAssignedTargets() { + return assignedToTargets; + } + + @Override + public List getInstalledTargets() { + return installedAtTargets; + } + + @Override + public String toString() { + return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision() + + ", getId()=" + getId() + "]"; + } + + @Override + public Set getModules() { + return Collections.unmodifiableSet(modules); + } + + @Override + public boolean addModule(final SoftwareModule softwareModule) { + + // we cannot allow that modules are added without a type defined + if (type == null) { + throw new DistributionSetTypeUndefinedException(); + } + + // check if it is allowed to such a module to this DS type + if (!type.containsModuleType(softwareModule.getType())) { + throw new UnsupportedSoftwareModuleForThisDistributionSetException(); + } + + final Optional found = modules.stream() + .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); + + if (found.isPresent()) { + return false; + } + + final long allready = modules.stream() + .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count(); + + if (allready >= softwareModule.getType().getMaxAssignments()) { + final Optional sameKey = modules.stream() + .filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst(); + modules.remove(sameKey.get()); + } + + if (modules.add(softwareModule)) { + complete = type.checkComplete(this); + return true; + } + + return false; + } + + @Override + public boolean removeModule(final SoftwareModule softwareModule) { + final Optional found = modules.stream() + .filter(module -> module.getId().equals(softwareModule.getId())).findFirst(); + + if (found.isPresent()) { + modules.remove(found.get()); + complete = type.checkComplete(this); + return true; + } + + return false; + + } + + @Override + public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) { + final Optional result = modules.stream().filter(module -> module.getType().equals(type)) + .findFirst(); + + if (result.isPresent()) { + return result.get(); + } + + return null; + } + + @Override + public DistributionSetType getType() { + return type; + } + + @Override + public void setType(final DistributionSetType type) { + this.type = type; + } + + @Override + public boolean isComplete() { + return complete; + } + + @Override + public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); + + } + + @Override + public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + final Map.Values> changeSet = EntityPropertyChangeHelper.getChangeSet( + JpaDistributionSet.class, descriptorEvent); + if (changeSet.containsKey(COMPLETE) + && changeSet.get(COMPLETE).getOldValue().equals(false) + && changeSet.get(COMPLETE).getNewValue().equals(true)) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post( + new DistributionCreatedEvent(jpaDistributionSet))); + } + + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); + + } + + @Override + public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 73d19086d..1cf1ccb77 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -1,223 +1,223 @@ -/** - * 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.util.List; - -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -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.AfterTransactionCommitExecutorHolder; -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.ActionType; -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.TotalTargetCountStatus; -import org.eclipse.persistence.descriptors.DescriptorEvent; - -/** - * JPA implementation of a {@link Rollout}. - * - */ -@Entity -@Table(name = "sp_rollout", indexes = { - @Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "name", "tenant" }, name = "uk_rollout")) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventAwareEntity { - - private static final long serialVersionUID = 1L; - - @OneToMany(targetEntity = JpaRolloutGroup.class) - @JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup")) - private List rolloutGroups; - - @Column(name = "target_filter", length = 1024, nullable = false) - private String targetFilterQuery; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds")) - private JpaDistributionSet distributionSet; - - @Column(name = "status") - private RolloutStatus status = RolloutStatus.CREATING; - - @Column(name = "last_check") - private long lastCheck; - - @Column(name = "action_type", nullable = false) - @Enumerated(EnumType.STRING) - private ActionType actionType = ActionType.FORCED; - - @Column(name = "forced_time") - private long forcedTime; - - @Column(name = "total_targets") - private long totalTargets; - - @Transient - @CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL) - private int rolloutGroupsTotal; - - @Transient - @CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED) - private int rolloutGroupsCreated; - - @Transient - private transient TotalTargetCountStatus totalTargetCountStatus; - - @Override - public DistributionSet getDistributionSet() { - return distributionSet; - } - - @Override - public void setDistributionSet(final DistributionSet distributionSet) { - this.distributionSet = (JpaDistributionSet) distributionSet; - } - - @Override - public List getRolloutGroups() { - return rolloutGroups; - } - - public void setRolloutGroups(final List rolloutGroups) { - this.rolloutGroups = rolloutGroups; - } - - @Override - public String getTargetFilterQuery() { - return targetFilterQuery; - } - - @Override - public void setTargetFilterQuery(final String targetFilterQuery) { - this.targetFilterQuery = targetFilterQuery; - } - - @Override - public RolloutStatus getStatus() { - return status; - } - - public void setStatus(final RolloutStatus status) { - this.status = status; - } - - public long getLastCheck() { - return lastCheck; - } - - public void setLastCheck(final long lastCheck) { - this.lastCheck = lastCheck; - } - - @Override - public ActionType getActionType() { - return actionType; - } - - @Override - public void setActionType(final ActionType actionType) { - this.actionType = actionType; - } - - @Override - public long getForcedTime() { - return forcedTime; - } - - @Override - public void setForcedTime(final long forcedTime) { - this.forcedTime = forcedTime; - } - - @Override - public long getTotalTargets() { - return totalTargets; - } - - public void setTotalTargets(final long totalTargets) { - this.totalTargets = totalTargets; - } - - public int getRolloutGroupsTotal() { - return rolloutGroupsTotal; - } - - public void setRolloutGroupsTotal(final int rolloutGroupsTotal) { - this.rolloutGroupsTotal = rolloutGroupsTotal; - } - - @Override - public int getRolloutGroupsCreated() { - return rolloutGroupsCreated; - } - - public void setRolloutGroupsCreated(final int rolloutGroupsCreated) { - this.rolloutGroupsCreated = rolloutGroupsCreated; - } - - @Override - public TotalTargetCountStatus getTotalTargetCountStatus() { - if (totalTargetCountStatus == null) { - totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); - } - return totalTargetCountStatus; - } - - public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { - this.totalTargetCountStatus = totalTargetCountStatus; - } - - @Override - public String toString() { - return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery - + ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck - + ", getName()=" + getName() + ", getId()=" + getId() + "]"; - } - - @Override - public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - - } - - @Override - public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). - post(new RolloutPropertyChangeEvent(jpaRollout, EntityPropertyChangeHelper.getChangeSet( - Rollout.class, descriptorEvent)))); - - } - - @Override - public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - - } - -} +/** + * 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.util.List; + +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; + +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.AfterTransactionCommitExecutorHolder; +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.ActionType; +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.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA implementation of a {@link Rollout}. + * + */ +@Entity +@Table(name = "sp_rollout", indexes = { + @Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "name", "tenant" }, name = "uk_rollout")) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventAwareEntity { + + private static final long serialVersionUID = 1L; + + @OneToMany(targetEntity = JpaRolloutGroup.class) + @JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup")) + private List rolloutGroups; + + @Column(name = "target_filter", length = 1024, nullable = false) + private String targetFilterQuery; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds")) + private JpaDistributionSet distributionSet; + + @Column(name = "status") + private RolloutStatus status = RolloutStatus.CREATING; + + @Column(name = "last_check") + private long lastCheck; + + @Column(name = "action_type", nullable = false) + @Enumerated(EnumType.STRING) + private ActionType actionType = ActionType.FORCED; + + @Column(name = "forced_time") + private long forcedTime; + + @Column(name = "total_targets") + private long totalTargets; + + @Transient + @CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL) + private int rolloutGroupsTotal; + + @Transient + @CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED) + private int rolloutGroupsCreated; + + @Transient + private transient TotalTargetCountStatus totalTargetCountStatus; + + @Override + public DistributionSet getDistributionSet() { + return distributionSet; + } + + @Override + public void setDistributionSet(final DistributionSet distributionSet) { + this.distributionSet = (JpaDistributionSet) distributionSet; + } + + @Override + public List getRolloutGroups() { + return rolloutGroups; + } + + public void setRolloutGroups(final List rolloutGroups) { + this.rolloutGroups = rolloutGroups; + } + + @Override + public String getTargetFilterQuery() { + return targetFilterQuery; + } + + @Override + public void setTargetFilterQuery(final String targetFilterQuery) { + this.targetFilterQuery = targetFilterQuery; + } + + @Override + public RolloutStatus getStatus() { + return status; + } + + public void setStatus(final RolloutStatus status) { + this.status = status; + } + + public long getLastCheck() { + return lastCheck; + } + + public void setLastCheck(final long lastCheck) { + this.lastCheck = lastCheck; + } + + @Override + public ActionType getActionType() { + return actionType; + } + + @Override + public void setActionType(final ActionType actionType) { + this.actionType = actionType; + } + + @Override + public long getForcedTime() { + return forcedTime; + } + + @Override + public void setForcedTime(final long forcedTime) { + this.forcedTime = forcedTime; + } + + @Override + public long getTotalTargets() { + return totalTargets; + } + + public void setTotalTargets(final long totalTargets) { + this.totalTargets = totalTargets; + } + + public int getRolloutGroupsTotal() { + return rolloutGroupsTotal; + } + + public void setRolloutGroupsTotal(final int rolloutGroupsTotal) { + this.rolloutGroupsTotal = rolloutGroupsTotal; + } + + @Override + public int getRolloutGroupsCreated() { + return rolloutGroupsCreated; + } + + public void setRolloutGroupsCreated(final int rolloutGroupsCreated) { + this.rolloutGroupsCreated = rolloutGroupsCreated; + } + + @Override + public TotalTargetCountStatus getTotalTargetCountStatus() { + if (totalTargetCountStatus == null) { + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + } + return totalTargetCountStatus; + } + + public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { + this.totalTargetCountStatus = totalTargetCountStatus; + } + + @Override + public String toString() { + return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery + + ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck + + ", getName()=" + getName() + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + + } + + @Override + public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). + post(new RolloutPropertyChangeEvent(jpaRollout, EntityPropertyChangeHelper.getChangeSet( + Rollout.class, descriptorEvent)))); + + } + + @Override + public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java index 6456a3e93..225fd458e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -1,261 +1,261 @@ -/** - * 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.util.ArrayList; -import java.util.List; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; - -import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; -import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; -import org.eclipse.hawkbit.repository.model.Rollout; -import org.eclipse.hawkbit.repository.model.RolloutGroup; -import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; -import org.eclipse.persistence.descriptors.DescriptorEvent; - -/** - * JPA entity definition of persisting a group of an rollout. - * - */ -@Entity -@Table(name = "sp_rolloutgroup", indexes = { - @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup,EventAwareEntity { - - private static final long serialVersionUID = 1L; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) - private JpaRollout rollout; - - @Column(name = "status") - private RolloutGroupStatus status = RolloutGroupStatus.READY; - - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class) - @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) - private final List rolloutTargetGroup = new ArrayList<>(); - - @ManyToOne(fetch = FetchType.LAZY) - private JpaRolloutGroup parent; - - @Column(name = "success_condition", nullable = false) - private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; - - @Column(name = "success_condition_exp", length = 512, nullable = false) - private String successConditionExp; - - @Column(name = "success_action", nullable = false) - private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; - - @Column(name = "success_action_exp", length = 512, nullable = false) - private String successActionExp; - - @Column(name = "error_condition") - private RolloutGroupErrorCondition errorCondition; - - @Column(name = "error_condition_exp", length = 512) - private String errorConditionExp; - - @Column(name = "error_action") - private RolloutGroupErrorAction errorAction; - - @Column(name = "error_action_exp", length = 512) - private String errorActionExp; - - @Column(name = "total_targets") - private long totalTargets; - - @Transient - private transient TotalTargetCountStatus totalTargetCountStatus; - - @Override - public Rollout getRollout() { - return rollout; - } - - @Override - public void setRollout(final Rollout rollout) { - this.rollout = (JpaRollout) rollout; - } - - @Override - public RolloutGroupStatus getStatus() { - return status; - } - - @Override - public void setStatus(final RolloutGroupStatus status) { - this.status = status; - } - - public List getRolloutTargetGroup() { - return rolloutTargetGroup; - } - - @Override - public RolloutGroup getParent() { - return parent; - } - - public void setParent(final RolloutGroup parent) { - this.parent = (JpaRolloutGroup) parent; - } - - @Override - public RolloutGroupSuccessCondition getSuccessCondition() { - return successCondition; - } - - @Override - public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { - successCondition = finishCondition; - } - - @Override - public String getSuccessConditionExp() { - return successConditionExp; - } - - @Override - public void setSuccessConditionExp(final String finishExp) { - successConditionExp = finishExp; - } - - @Override - public RolloutGroupErrorCondition getErrorCondition() { - return errorCondition; - } - - @Override - public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { - this.errorCondition = errorCondition; - } - - @Override - public String getErrorConditionExp() { - return errorConditionExp; - } - - @Override - public void setErrorConditionExp(final String errorExp) { - errorConditionExp = errorExp; - } - - @Override - public RolloutGroupErrorAction getErrorAction() { - return errorAction; - } - - @Override - public void setErrorAction(final RolloutGroupErrorAction errorAction) { - this.errorAction = errorAction; - } - - @Override - public String getErrorActionExp() { - return errorActionExp; - } - - @Override - public void setErrorActionExp(final String errorActionExp) { - this.errorActionExp = errorActionExp; - } - - @Override - public RolloutGroupSuccessAction getSuccessAction() { - return successAction; - } - - @Override - public String getSuccessActionExp() { - return successActionExp; - } - - @Override - public long getTotalTargets() { - return totalTargets; - } - - public void setTotalTargets(final long totalTargets) { - this.totalTargets = totalTargets; - } - - public void setSuccessAction(final RolloutGroupSuccessAction successAction) { - this.successAction = successAction; - } - - public void setSuccessActionExp(final String successActionExp) { - this.successActionExp = successActionExp; - } - - /** - * @return the totalTargetCountStatus - */ - @Override - public TotalTargetCountStatus getTotalTargetCountStatus() { - if (totalTargetCountStatus == null) { - totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); - } - return totalTargetCountStatus; - } - - /** - * @param totalTargetCountStatus - * the totalTargetCountStatus to set - */ - @Override - public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { - this.totalTargetCountStatus = totalTargetCountStatus; - } - - @Override - public String toString() { - return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup - + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp - + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() - + ", getId()=" + getId() + "]"; - } - - @Override - public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - - } - - @Override - public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). - post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, - EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); - } - - @Override - public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - - } - -} +/** + * 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.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; + +import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +import org.eclipse.hawkbit.repository.model.Rollout; +import org.eclipse.hawkbit.repository.model.RolloutGroup; +import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus; +import org.eclipse.persistence.descriptors.DescriptorEvent; + +/** + * JPA entity definition of persisting a group of an rollout. + * + */ +@Entity +@Table(name = "sp_rolloutgroup", indexes = { + @Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "name", "rollout", "tenant" }, name = "uk_rolloutgroup")) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup,EventAwareEntity { + + private static final long serialVersionUID = 1L; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout")) + private JpaRollout rollout; + + @Column(name = "status") + private RolloutGroupStatus status = RolloutGroupStatus.READY; + + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class) + @JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false) + private final List rolloutTargetGroup = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + private JpaRolloutGroup parent; + + @Column(name = "success_condition", nullable = false) + private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD; + + @Column(name = "success_condition_exp", length = 512, nullable = false) + private String successConditionExp; + + @Column(name = "success_action", nullable = false) + private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP; + + @Column(name = "success_action_exp", length = 512, nullable = false) + private String successActionExp; + + @Column(name = "error_condition") + private RolloutGroupErrorCondition errorCondition; + + @Column(name = "error_condition_exp", length = 512) + private String errorConditionExp; + + @Column(name = "error_action") + private RolloutGroupErrorAction errorAction; + + @Column(name = "error_action_exp", length = 512) + private String errorActionExp; + + @Column(name = "total_targets") + private long totalTargets; + + @Transient + private transient TotalTargetCountStatus totalTargetCountStatus; + + @Override + public Rollout getRollout() { + return rollout; + } + + @Override + public void setRollout(final Rollout rollout) { + this.rollout = (JpaRollout) rollout; + } + + @Override + public RolloutGroupStatus getStatus() { + return status; + } + + @Override + public void setStatus(final RolloutGroupStatus status) { + this.status = status; + } + + public List getRolloutTargetGroup() { + return rolloutTargetGroup; + } + + @Override + public RolloutGroup getParent() { + return parent; + } + + public void setParent(final RolloutGroup parent) { + this.parent = (JpaRolloutGroup) parent; + } + + @Override + public RolloutGroupSuccessCondition getSuccessCondition() { + return successCondition; + } + + @Override + public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) { + successCondition = finishCondition; + } + + @Override + public String getSuccessConditionExp() { + return successConditionExp; + } + + @Override + public void setSuccessConditionExp(final String finishExp) { + successConditionExp = finishExp; + } + + @Override + public RolloutGroupErrorCondition getErrorCondition() { + return errorCondition; + } + + @Override + public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) { + this.errorCondition = errorCondition; + } + + @Override + public String getErrorConditionExp() { + return errorConditionExp; + } + + @Override + public void setErrorConditionExp(final String errorExp) { + errorConditionExp = errorExp; + } + + @Override + public RolloutGroupErrorAction getErrorAction() { + return errorAction; + } + + @Override + public void setErrorAction(final RolloutGroupErrorAction errorAction) { + this.errorAction = errorAction; + } + + @Override + public String getErrorActionExp() { + return errorActionExp; + } + + @Override + public void setErrorActionExp(final String errorActionExp) { + this.errorActionExp = errorActionExp; + } + + @Override + public RolloutGroupSuccessAction getSuccessAction() { + return successAction; + } + + @Override + public String getSuccessActionExp() { + return successActionExp; + } + + @Override + public long getTotalTargets() { + return totalTargets; + } + + public void setTotalTargets(final long totalTargets) { + this.totalTargets = totalTargets; + } + + public void setSuccessAction(final RolloutGroupSuccessAction successAction) { + this.successAction = successAction; + } + + public void setSuccessActionExp(final String successActionExp) { + this.successActionExp = successActionExp; + } + + /** + * @return the totalTargetCountStatus + */ + @Override + public TotalTargetCountStatus getTotalTargetCountStatus() { + if (totalTargetCountStatus == null) { + totalTargetCountStatus = new TotalTargetCountStatus(totalTargets); + } + return totalTargetCountStatus; + } + + /** + * @param totalTargetCountStatus + * the totalTargetCountStatus to set + */ + @Override + public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) { + this.totalTargetCountStatus = totalTargetCountStatus; + } + + @Override + public String toString() { + return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup + + ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp + + ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName() + + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + + } + + @Override + public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). + post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, + EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); + } + + @Override + public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index f6a2b8346..431ebb102 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -1,257 +1,257 @@ -/** - * 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.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; -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.TargetUpdatedEvent; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; -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; -import org.eclipse.hawkbit.repository.model.Action; -import org.eclipse.hawkbit.repository.model.DistributionSet; -import org.eclipse.hawkbit.repository.model.Target; -import org.eclipse.hawkbit.repository.model.TargetInfo; -import org.eclipse.hawkbit.repository.model.TargetTag; -import org.eclipse.persistence.annotations.CascadeOnDelete; -import org.eclipse.persistence.descriptors.DescriptorEvent; -import org.springframework.data.domain.Persistable; - -/** - * JPA implementation of {@link Target}. - * - */ -@Entity -@Table(name = "sp_target", indexes = { - @Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"), - @Index(name = "sp_idx_target_02", columnList = "tenant,name"), - @Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"), - @Index(name = "sp_idx_target_04", columnList = "tenant,created_at"), - @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { - "controller_id", "tenant" }, name = "uk_tenant_controller_id")) -@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"), - @NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") }) -// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for -// sub entities -@SuppressWarnings("squid:S2160") -public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { - private static final long serialVersionUID = 1L; - - @Column(name = "controller_id", length = 64) - @Size(min = 1) - @NotNull - private String controllerId; - - @Transient - private boolean entityNew; - - @ManyToMany(targetEntity = JpaTargetTag.class) - @JoinTable(name = "sp_target_target_tag", joinColumns = { - @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = { - @JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) }) - private Set tags = new HashSet<>(); - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { - CascadeType.REMOVE }, targetEntity = JpaAction.class) - @JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ")) - private final List actions = new ArrayList<>(); - - @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class) - @JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds")) - private JpaDistributionSet assignedDistributionSet; - - @CascadeOnDelete - @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class) - @PrimaryKeyJoinColumn - private JpaTargetInfo targetInfo; - - /** - * the security token of the target which allows if enabled to authenticate - * with this security token. - */ - @Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128) - private String securityToken; - - @CascadeOnDelete - @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) - @JoinColumn(name = "target_Id", insertable = false, updatable = false) - private final List rolloutTargetGroup = new ArrayList<>(); - - /** - * Constructor. - * - * @param controllerId - * 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); - this.securityToken = securityToken; - targetInfo = new JpaTargetInfo(this); - } - - /** - * empty constructor for JPA. - */ - JpaTarget() { - controllerId = null; - securityToken = null; - } - - @Override - public DistributionSet getAssignedDistributionSet() { - return assignedDistributionSet; - } - - @Override - public String getControllerId() { - return controllerId; - } - - @Override - public Set getTags() { - return tags; - } - - public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) { - this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet; - } - - public void setControllerId(final String controllerId) { - this.controllerId = controllerId; - } - - public void setTags(final Set tags) { - this.tags = tags; - } - - @Override - public List getActions() { - return actions; - } - - @Override - @Transient - public boolean isNew() { - return entityNew; - } - - /** - * @param isNew - * the isNew to set - */ - public void setNew(final boolean entityNew) { - this.entityNew = entityNew; - } - - /** - * @return the targetInfo - */ - @Override - public TargetInfo getTargetInfo() { - return targetInfo; - } - - /** - * @param targetInfo - * the targetInfo to set - */ - public void setTargetInfo(final TargetInfo targetInfo) { - this.targetInfo = (JpaTargetInfo) targetInfo; - } - - /** - * @return the securityToken if the current security context contains the - * necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN} - * or the current context is executed as system code, otherwise - * {@code null}. - */ - @Override - public String getSecurityToken() { - if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode() - || SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) { - return securityToken; - } - return null; - } - - /** - * @param securityToken - * the securityToken to set - */ - @Override - public void setSecurityToken(final String securityToken) { - this.securityToken = securityToken; - } - - @Override - public String toString() { - return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]"; - } - - @Override - public void fireCreateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); - } - - @Override - public void fireUpdateEvent(final JpaTarget jpaTarget,final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); - - } - - @Override - public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - - - } - -} +/** + * 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.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Table; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; +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.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; +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; +import org.eclipse.hawkbit.repository.model.Action; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetInfo; +import org.eclipse.hawkbit.repository.model.TargetTag; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.springframework.data.domain.Persistable; + +/** + * JPA implementation of {@link Target}. + * + */ +@Entity +@Table(name = "sp_target", indexes = { + @Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"), + @Index(name = "sp_idx_target_02", columnList = "tenant,name"), + @Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"), + @Index(name = "sp_idx_target_04", columnList = "tenant,created_at"), + @Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = { + "controller_id", "tenant" }, name = "uk_tenant_controller_id")) +@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"), + @NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") }) +// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for +// sub entities +@SuppressWarnings("squid:S2160") +public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { + private static final long serialVersionUID = 1L; + + @Column(name = "controller_id", length = 64) + @Size(min = 1) + @NotNull + private String controllerId; + + @Transient + private boolean entityNew; + + @ManyToMany(targetEntity = JpaTargetTag.class) + @JoinTable(name = "sp_target_target_tag", joinColumns = { + @JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = { + @JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) }) + private Set tags = new HashSet<>(); + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = { + CascadeType.REMOVE }, targetEntity = JpaAction.class) + @JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ")) + private final List actions = new ArrayList<>(); + + @ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class) + @JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds")) + private JpaDistributionSet assignedDistributionSet; + + @CascadeOnDelete + @OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class) + @PrimaryKeyJoinColumn + private JpaTargetInfo targetInfo; + + /** + * the security token of the target which allows if enabled to authenticate + * with this security token. + */ + @Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128) + private String securityToken; + + @CascadeOnDelete + @OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST }) + @JoinColumn(name = "target_Id", insertable = false, updatable = false) + private final List rolloutTargetGroup = new ArrayList<>(); + + /** + * Constructor. + * + * @param controllerId + * 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); + this.securityToken = securityToken; + targetInfo = new JpaTargetInfo(this); + } + + /** + * empty constructor for JPA. + */ + JpaTarget() { + controllerId = null; + securityToken = null; + } + + @Override + public DistributionSet getAssignedDistributionSet() { + return assignedDistributionSet; + } + + @Override + public String getControllerId() { + return controllerId; + } + + @Override + public Set getTags() { + return tags; + } + + public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) { + this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet; + } + + public void setControllerId(final String controllerId) { + this.controllerId = controllerId; + } + + public void setTags(final Set tags) { + this.tags = tags; + } + + @Override + public List getActions() { + return actions; + } + + @Override + @Transient + public boolean isNew() { + return entityNew; + } + + /** + * @param isNew + * the isNew to set + */ + public void setNew(final boolean entityNew) { + this.entityNew = entityNew; + } + + /** + * @return the targetInfo + */ + @Override + public TargetInfo getTargetInfo() { + return targetInfo; + } + + /** + * @param targetInfo + * the targetInfo to set + */ + public void setTargetInfo(final TargetInfo targetInfo) { + this.targetInfo = (JpaTargetInfo) targetInfo; + } + + /** + * @return the securityToken if the current security context contains the + * necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN} + * or the current context is executed as system code, otherwise + * {@code null}. + */ + @Override + public String getSecurityToken() { + if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode() + || SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) { + return securityToken; + } + return null; + } + + /** + * @param securityToken + * the securityToken to set + */ + @Override + public void setSecurityToken(final String securityToken) { + this.securityToken = securityToken; + } + + @Override + public String toString() { + return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]"; + } + + @Override + public void fireCreateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); + } + + @Override + public void fireUpdateEvent(final JpaTarget jpaTarget,final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); + + } + + @Override + public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { + + + } + +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index a21c7547f..bfae18248 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -1,344 +1,344 @@ -/** - * 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.net.URI; -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.persistence.CascadeType; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ConstraintMode; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.ForeignKey; -import javax.persistence.Id; -import javax.persistence.Index; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapsId; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Transient; - -import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; -import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -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.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; -import org.eclipse.persistence.annotations.CascadeOnDelete; -import org.eclipse.persistence.descriptors.DescriptorEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Persistable; - -/** - * A table which contains all the information inserted, updated by the - * controller itself. So this entity does not provide audit information because - * changes on this entity are mostly only done by controller requests. That's - * the reason that we store these information in a separated table so we don't - * modifying the {@link Target} itself when a controller reports it's - * {@link #lastTargetQuery} for example. - * - */ -@Table(name = "sp_target_info", indexes = { - @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) -@Entity -@EntityListeners(EntityPropertyChangeListener.class) -public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { - private static final long serialVersionUID = 1L; - - private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); - - @Id - private Long targetId; - - @Transient - private boolean entityNew; - - @CascadeOnDelete - @OneToOne(cascade = { CascadeType.MERGE, - CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class) - @JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ")) - @MapsId - private JpaTarget target; - - @Column(name = "address", length = 512) - private String address; - - @Column(name = "last_target_query") - private Long lastTargetQuery; - - @Column(name = "install_date") - private Long installationDate; - - @Column(name = "update_status", nullable = false, length = 255) - @Enumerated(EnumType.STRING) - private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN; - - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds")) - private JpaDistributionSet installedDistributionSet; - - /** - * Read only on management API. Are commited by controller. - */ - @ElementCollection - @Column(name = "attribute_value", length = 128) - @MapKeyColumn(name = "attribute_key", nullable = false, length = 32) - @CollectionTable(name = "sp_target_attributes", joinColumns = { - @JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target")) - - private final Map controllerAttributes = Collections.synchronizedMap(new HashMap()); - - // set default request controller attributes to true, because we want to - // request them the first - // time - @Column(name = "request_controller_attributes", nullable = false) - private boolean requestControllerAttributes = true; - - /** - * Constructor for {@link TargetStatus}. - * - * @param target - * related to this status. - */ - public JpaTargetInfo(final JpaTarget target) { - this.target = target; - targetId = target.getId(); - } - - JpaTargetInfo() { - target = null; - targetId = null; - } - - @Override - public Long getId() { - return targetId; - } - - @Override - @Transient - public boolean isNew() { - return entityNew; - } - - /** - * @param isNew - * the isNew to set - */ - public void setNew(final boolean entityNew) { - this.entityNew = entityNew; - } - - /** - * @return the ipAddress - */ - @Override - public URI getAddress() { - if (address == null) { - return null; - } - try { - return URI.create(address); - } catch (final IllegalArgumentException e) { - LOG.warn("Invalid address provided. Cloud not be configured to URI", e); - return null; - } - } - - /** - * @param address - * the target address to set - * - * @throws IllegalArgumentException - * If the given string violates RFC 2396 - */ - @Override - public void setAddress(final String address) { - // check if this is a real URI - if (address != null) { - try { - URI.create(address); - } catch (final IllegalArgumentException e) { - throw new InvalidTargetAddressException( - "The given address " + address + " violates the RFC-2396 specification", e); - } - } - - this.address = address; - } - - public Long getTargetId() { - return targetId; - } - - public void setTargetId(final Long targetId) { - this.targetId = targetId; - } - - @Override - public Target getTarget() { - return target; - } - - public void setTarget(final JpaTarget target) { - this.target = target; - } - - @Override - public Long getLastTargetQuery() { - return lastTargetQuery; - } - - public void setLastTargetQuery(final Long lastTargetQuery) { - this.lastTargetQuery = lastTargetQuery; - } - - public void setRequestControllerAttributes(final boolean requestControllerAttributes) { - this.requestControllerAttributes = requestControllerAttributes; - } - - @Override - public Map getControllerAttributes() { - return controllerAttributes; - } - - @Override - public boolean isRequestControllerAttributes() { - return requestControllerAttributes; - } - - @Override - public Long getInstallationDate() { - return installationDate; - } - - public void setInstallationDate(final Long installationDate) { - this.installationDate = installationDate; - } - - @Override - public TargetUpdateStatus getUpdateStatus() { - return updateStatus; - } - - public void setUpdateStatus(final TargetUpdateStatus updateStatus) { - this.updateStatus = updateStatus; - } - - @Override - public DistributionSet getInstalledDistributionSet() { - return installedDistributionSet; - } - - public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) { - this.installedDistributionSet = installedDistributionSet; - } - - /** - * @return the poll time which holds the last poll time of the target, the - * next poll time and the overdue time. In case the - * {@link #lastTargetQuery} is not set e.g. the target never polled - * before this method returns {@code null} - */ - @Override - public PollStatus getPollStatus() { - if (lastTargetQuery == null) { - return null; - } - return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> { - final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder - .getInstance().getTenantConfigurationManagement() - .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); - final Duration overdueTime = DurationHelper.formattedStringToDuration( - TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() - .getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) - .getValue()); - final LocalDateTime currentDate = LocalDateTime.now(); - final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), - ZoneId.systemDefault()); - final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); - final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); - return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); - }); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((target == null) ? 0 : target.hashCode()); - result = prime * result + ((targetId == null) ? 0 : targetId.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof TargetInfo)) { - return false; - } - final JpaTargetInfo other = (JpaTargetInfo) obj; - if (target == null) { - if (other.target != null) { - return false; - } - } else if (!target.equals(other.target)) { - return false; - } - if (targetId == null) { - if (other.targetId != null) { - return false; - } - } else if (!targetId.equals(other.targetId)) { - return false; - } - return true; - } - - @Override - public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo,final DescriptorEvent descriptorEvent) { - // there is no target info created event - } - - @Override - public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); - } - - @Override - public void fireDeleteEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { - } -} +/** + * 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.net.URI; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapsId; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Transient; + +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; +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.tenancy.configuration.DurationHelper; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.persistence.annotations.CascadeOnDelete; +import org.eclipse.persistence.descriptors.DescriptorEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Persistable; + +/** + * A table which contains all the information inserted, updated by the + * controller itself. So this entity does not provide audit information because + * changes on this entity are mostly only done by controller requests. That's + * the reason that we store these information in a separated table so we don't + * modifying the {@link Target} itself when a controller reports it's + * {@link #lastTargetQuery} for example. + * + */ +@Table(name = "sp_target_info", indexes = { + @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) +@Entity +@EntityListeners(EntityPropertyChangeListener.class) +public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { + private static final long serialVersionUID = 1L; + + private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); + + @Id + private Long targetId; + + @Transient + private boolean entityNew; + + @CascadeOnDelete + @OneToOne(cascade = { CascadeType.MERGE, + CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class) + @JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ")) + @MapsId + private JpaTarget target; + + @Column(name = "address", length = 512) + private String address; + + @Column(name = "last_target_query") + private Long lastTargetQuery; + + @Column(name = "install_date") + private Long installationDate; + + @Column(name = "update_status", nullable = false, length = 255) + @Enumerated(EnumType.STRING) + private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN; + + @ManyToOne(optional = true, fetch = FetchType.LAZY) + @JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds")) + private JpaDistributionSet installedDistributionSet; + + /** + * Read only on management API. Are commited by controller. + */ + @ElementCollection + @Column(name = "attribute_value", length = 128) + @MapKeyColumn(name = "attribute_key", nullable = false, length = 32) + @CollectionTable(name = "sp_target_attributes", joinColumns = { + @JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target")) + + private final Map controllerAttributes = Collections.synchronizedMap(new HashMap()); + + // set default request controller attributes to true, because we want to + // request them the first + // time + @Column(name = "request_controller_attributes", nullable = false) + private boolean requestControllerAttributes = true; + + /** + * Constructor for {@link TargetStatus}. + * + * @param target + * related to this status. + */ + public JpaTargetInfo(final JpaTarget target) { + this.target = target; + targetId = target.getId(); + } + + JpaTargetInfo() { + target = null; + targetId = null; + } + + @Override + public Long getId() { + return targetId; + } + + @Override + @Transient + public boolean isNew() { + return entityNew; + } + + /** + * @param isNew + * the isNew to set + */ + public void setNew(final boolean entityNew) { + this.entityNew = entityNew; + } + + /** + * @return the ipAddress + */ + @Override + public URI getAddress() { + if (address == null) { + return null; + } + try { + return URI.create(address); + } catch (final IllegalArgumentException e) { + LOG.warn("Invalid address provided. Cloud not be configured to URI", e); + return null; + } + } + + /** + * @param address + * the target address to set + * + * @throws IllegalArgumentException + * If the given string violates RFC 2396 + */ + @Override + public void setAddress(final String address) { + // check if this is a real URI + if (address != null) { + try { + URI.create(address); + } catch (final IllegalArgumentException e) { + throw new InvalidTargetAddressException( + "The given address " + address + " violates the RFC-2396 specification", e); + } + } + + this.address = address; + } + + public Long getTargetId() { + return targetId; + } + + public void setTargetId(final Long targetId) { + this.targetId = targetId; + } + + @Override + public Target getTarget() { + return target; + } + + public void setTarget(final JpaTarget target) { + this.target = target; + } + + @Override + public Long getLastTargetQuery() { + return lastTargetQuery; + } + + public void setLastTargetQuery(final Long lastTargetQuery) { + this.lastTargetQuery = lastTargetQuery; + } + + public void setRequestControllerAttributes(final boolean requestControllerAttributes) { + this.requestControllerAttributes = requestControllerAttributes; + } + + @Override + public Map getControllerAttributes() { + return controllerAttributes; + } + + @Override + public boolean isRequestControllerAttributes() { + return requestControllerAttributes; + } + + @Override + public Long getInstallationDate() { + return installationDate; + } + + public void setInstallationDate(final Long installationDate) { + this.installationDate = installationDate; + } + + @Override + public TargetUpdateStatus getUpdateStatus() { + return updateStatus; + } + + public void setUpdateStatus(final TargetUpdateStatus updateStatus) { + this.updateStatus = updateStatus; + } + + @Override + public DistributionSet getInstalledDistributionSet() { + return installedDistributionSet; + } + + public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) { + this.installedDistributionSet = installedDistributionSet; + } + + /** + * @return the poll time which holds the last poll time of the target, the + * next poll time and the overdue time. In case the + * {@link #lastTargetQuery} is not set e.g. the target never polled + * before this method returns {@code null} + */ + @Override + public PollStatus getPollStatus() { + if (lastTargetQuery == null) { + return null; + } + return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> { + final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder + .getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); + final Duration overdueTime = DurationHelper.formattedStringToDuration( + TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement() + .getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class) + .getValue()); + final LocalDateTime currentDate = LocalDateTime.now(); + final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery), + ZoneId.systemDefault()); + final LocalDateTime nextPollDate = lastPollDate.plus(pollTime); + final LocalDateTime overdueDate = nextPollDate.plus(overdueTime); + return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate); + }); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((target == null) ? 0 : target.hashCode()); + result = prime * result + ((targetId == null) ? 0 : targetId.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof TargetInfo)) { + return false; + } + final JpaTargetInfo other = (JpaTargetInfo) obj; + if (target == null) { + if (other.target != null) { + return false; + } + } else if (!target.equals(other.target)) { + return false; + } + if (targetId == null) { + if (other.targetId != null) { + return false; + } + } else if (!targetId.equals(other.targetId)) { + return false; + } + return true; + } + + @Override + public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo,final DescriptorEvent descriptorEvent) { + // there is no target info created event + } + + @Override + public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); + } + + @Override + public void fireDeleteEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + } +} From 9c468c76f04b385ba9fbf28dd44cd80edc2d3b05 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Fri, 29 Jul 2016 13:12:51 +0200 Subject: [PATCH 06/28] Fix for EOL. --- .../eclipse/hawkbit/repository/DistributionSetManagement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java index b3b4fd86f..c405dccf4 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/DistributionSetManagement.java @@ -289,7 +289,7 @@ public interface DistributionSetManagement { * * @param distributionSetId * the distribution set id to retrieve the meta data from - * @return list of distributionSetMetadata for a given distribution set Id + * @return list of distributionSetMetadata for a given distribution set Id. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) List findDistributionSetMetadataByDistributionSetId(@NotNull Long distributionSetId); From dfd449592cded96d177c1c04deb046c7dd7a3b80 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Fri, 29 Jul 2016 13:22:38 +0200 Subject: [PATCH 07/28] Fix for EOL from widows EOL to unix EOL --- .../repository/SoftwareManagement.java | 2 +- .../repository/jpa/JpaSoftwareManagement.java | 13 ++++---- .../repository/jpa/model/JpaAction.java | 17 ++++++----- .../jpa/model/JpaDistributionSet.java | 30 +++++++++---------- .../repository/jpa/model/JpaRollout.java | 14 ++++----- .../repository/jpa/model/JpaRolloutGroup.java | 13 ++++---- .../repository/jpa/model/JpaTarget.java | 16 +++++----- .../repository/jpa/model/JpaTargetInfo.java | 5 ++-- 8 files changed, 58 insertions(+), 52 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java index bb73dbb30..9b4426ff2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareManagement.java @@ -496,7 +496,7 @@ public interface SoftwareManagement { * @throws RSQLParameterSyntaxException * if the RSQL syntax is wrong * @return result of all meta data entries for a given software - * module id + * module id. */ @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY) List findSoftwareModuleMetadataBySoftwareModuleId(Long softwareModuleId); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java index 31b222051..3f8c1a54b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareManagement.java @@ -620,14 +620,15 @@ public class JpaSoftwareManagement implements SoftwareManagement { pageable), pageable); } - + @Override public List findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) { - return new ArrayList<> ( softwareModuleMetadataRepository - .findAll( - (Specification) (root, query, cb) -> cb.and( - cb.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule) - .get(JpaSoftwareModule_.id), softwareModuleId)))); + return new ArrayList<>( + softwareModuleMetadataRepository + .findAll((Specification) (root, query, + cb) -> cb.and(cb.equal( + root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), + softwareModuleId)))); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index 5bda8f63b..e7bb04c04 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -55,7 +55,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action,EventAwareEntity { +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity { private static final long serialVersionUID = 1L; @ManyToOne(fetch = FetchType.LAZY) @@ -179,21 +179,22 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio @Override public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); - + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() + .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); + } @Override public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus(). - post(new ActionPropertyChangeEvent(jpaAction, EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post(new ActionPropertyChangeEvent(jpaAction, + EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); } - - + @Override public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index 77a5f88fd..afbddbade 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -69,9 +69,10 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet,EventAwareEntity { +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity + implements DistributionSet, EventAwareEntity { private static final long serialVersionUID = 1L; - + private static final String COMPLETE = "complete"; @Column(name = "required_migration_step") @@ -291,30 +292,29 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen @Override public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); - + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder + .getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); + } @Override public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - final Map.Values> changeSet = EntityPropertyChangeHelper.getChangeSet( - JpaDistributionSet.class, descriptorEvent); - if (changeSet.containsKey(COMPLETE) - && changeSet.get(COMPLETE).getOldValue().equals(false) + final Map.Values> changeSet = EntityPropertyChangeHelper + .getChangeSet(JpaDistributionSet.class, descriptorEvent); + if (changeSet.containsKey(COMPLETE) && changeSet.get(COMPLETE).getOldValue().equals(false) && changeSet.get(COMPLETE).getNewValue().equals(true)) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post( - new DistributionCreatedEvent(jpaDistributionSet))); + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder + .getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); } - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); - + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder + .getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); + } @Override public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 1cf1ccb77..57c4d8a69 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -49,7 +49,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventAwareEntity { +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -204,20 +204,20 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventA @Override public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - + } @Override public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). - post(new RolloutPropertyChangeEvent(jpaRollout, EntityPropertyChangeHelper.getChangeSet( - Rollout.class, descriptorEvent)))); - + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post(new RolloutPropertyChangeEvent(jpaRollout, + EntityPropertyChangeHelper.getChangeSet(Rollout.class, descriptorEvent)))); + } @Override public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java index 225fd458e..0b7a23985 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -45,7 +45,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup,EventAwareEntity { +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -243,19 +243,20 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr @Override public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - + } @Override public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus(). - post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, - EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() + .afterCommit(() -> EventBusHolder.getInstance().getEventBus() + .post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, + EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); } @Override public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index 431ebb102..d67d8e9d1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -69,7 +69,8 @@ import org.springframework.data.domain.Persistable; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { +public class JpaTarget extends AbstractJpaNamedEntity + implements Persistable, Target, EventAwareEntity { private static final long serialVersionUID = 1L; @Column(name = "controller_id", length = 64) @@ -239,19 +240,20 @@ public class JpaTarget extends AbstractJpaNamedEntity implements PersistableEventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() + .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); } @Override - public void fireUpdateEvent(final JpaTarget jpaTarget,final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); - + public void fireUpdateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() + .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); + } @Override public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - - + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index bfae18248..59cff35c8 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -329,13 +329,14 @@ public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareE } @Override - public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo,final DescriptorEvent descriptorEvent) { + public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { // there is no target info created event } @Override public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( + () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); } @Override From 5be513422de8c89fc52781976f023c677a45f869 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Mon, 1 Aug 2016 10:24:09 +0200 Subject: [PATCH 08/28] remove notification of target deletion from management layer Signed-off-by: Michael Hirsch --- .../repository/jpa/JpaTargetManagement.java | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 30a5dd5d9..1cd2ffc3c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -29,7 +29,6 @@ import javax.persistence.criteria.Root; 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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -49,7 +48,6 @@ import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; 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.data.domain.Page; @@ -98,10 +96,6 @@ public class JpaTargetManagement implements TargetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; - - - @Autowired - private TenantAware tenantAware; @Override public Target findTargetByControllerID(final String controllerId) { @@ -208,14 +202,12 @@ public class JpaTargetManagement implements TargetManagement { // hibernate session. final List targetsForCurrentTenant = targetRepository.findAll(Lists.newArrayList(targetIDs)).stream() .map(Target::getId).collect(Collectors.toList()); - if (!targetsForCurrentTenant.isEmpty()) { - targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); - targetRepository.deleteByIdIn(targetsForCurrentTenant); - targetsForCurrentTenant.forEach(targetId -> notifyTargetDeleted( - tenantAware.getCurrentTenant(), targetId)); - } + if (!targetsForCurrentTenant.isEmpty()) { + targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); + targetRepository.deleteByIdIn(targetsForCurrentTenant); + } } - + @Override public Page findTargetByAssignedDistributionSet(final Long distributionSetID, final Pageable pageReq) { return targetRepository.findByAssignedDistributionSetId(pageReq, distributionSetID); @@ -659,9 +651,5 @@ public class JpaTargetManagement implements TargetManagement { } return resultList; } - - private void notifyTargetDeleted(final String tenant, final Long targetId) { - afterCommit.afterCommit(() -> eventBus.post(new TargetDeletedEvent(tenant, targetId))); - } } From 72899df4a46cb6b5304857d96972a793bd7a7768 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Mon, 1 Aug 2016 10:30:45 +0200 Subject: [PATCH 09/28] remove notification of distribution set deletion from management layer Signed-off-by: Michael Hirsch --- .../repository/jpa/JpaDistributionSetManagement.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 306b9bd80..84c81966f 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -28,7 +28,6 @@ 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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityLockedException; @@ -55,7 +54,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; 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.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -104,9 +102,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; - @Autowired - private TenantAware tenantAware; - @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); @@ -198,10 +193,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { // handle the empty list distributionSetRepository.deleteByIdIn(toHardDelete); } - - afterCommit.afterCommit( - () -> eventBus.post(new DistributionDeletedEvent(tenantAware.getCurrentTenant(), distributionSetIDs))); - } @Override @@ -527,14 +518,12 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) { - entityManager.merge((JpaDistributionSet) distributionSet).setLastModifiedAt(0L); distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key)); } @Override public Page findDistributionSetMetadataByDistributionSetId(final Long distributionSetId, final Pageable pageable) { - return convertMdPage(distributionSetMetadataRepository .findAll((Specification) (root, query, cb) -> cb.equal( root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), @@ -544,7 +533,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Override public List findDistributionSetMetadataByDistributionSetId(final Long distributionSetId) { - return new ArrayList(distributionSetMetadataRepository .findAll((Specification) (root, query, cb) -> cb.equal( root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id), From 4e237f748bad38dec815360226abf5cc012172e6 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Mon, 1 Aug 2016 13:01:25 +0200 Subject: [PATCH 10/28] refactor the EventAwareEntity interface Signed-off-by: Michael Hirsch --- .../model/EntityPropertyChangeListener.java | 26 +++++++++--- .../jpa/model/EventAwareEntity.java | 40 +++++++++---------- .../repository/jpa/model/JpaAction.java | 21 ++++------ .../jpa/model/JpaDistributionSet.java | 39 +++++++++--------- .../repository/jpa/model/JpaRollout.java | 24 +++++------ .../repository/jpa/model/JpaRolloutGroup.java | 20 ++++------ .../repository/jpa/model/JpaTarget.java | 21 ++++------ .../repository/jpa/model/JpaTargetInfo.java | 13 +++--- 8 files changed, 101 insertions(+), 103 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index df36309df..13b1507db 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.repository.jpa.model; +import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; @@ -19,21 +20,34 @@ public class EntityPropertyChangeListener extends DescriptorEventAdapter { @Override public void postInsert(final DescriptorEvent event) { - final Object object = event.getObject(); - if (object instanceof EventAwareEntity) { - ((EventAwareEntity) object).fireCreateEvent(object,event); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireCreateEvent(event)); } } @Override public void postUpdate(final DescriptorEvent event) { - final Object object = event.getObject(); - if (object instanceof EventAwareEntity) { - ((EventAwareEntity) object).fireUpdateEvent(object,event); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireUpdateEvent(event)); } } + @Override + public void postDelete(final DescriptorEvent event) { + final Object object = event.getObject(); + if (isEventAwareEntity(object)) { + doNotifiy(() -> ((EventAwareEntity) object).fireDeleteEvent(event)); + } + } + + private boolean isEventAwareEntity(final Object object) { + return object instanceof EventAwareEntity; + } + + private void doNotifiy(final Runnable runnable) { + AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(runnable); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java index 2c1fe51d2..1c6f217c9 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java @@ -1,20 +1,20 @@ -/** - * 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 org.eclipse.persistence.descriptors.DescriptorEvent; - -public interface EventAwareEntity { - - public void fireCreateEvent(T t,DescriptorEvent descriptorEvent); - - public void fireUpdateEvent(T t,DescriptorEvent descriptorEvent); - - public void fireDeleteEvent(T t,DescriptorEvent descriptorEvent); -} +/** + * 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 org.eclipse.persistence.descriptors.DescriptorEvent; + +public interface EventAwareEntity { + + void fireCreateEvent(DescriptorEvent descriptorEvent); + + void fireUpdateEvent(DescriptorEvent descriptorEvent); + + void fireDeleteEvent(DescriptorEvent descriptorEvent); +} diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index e7bb04c04..72ef46ba3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -30,7 +30,6 @@ import javax.persistence.Table; import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent; import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; 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; @@ -55,7 +54,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity { +public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action, EventAwareEntity { private static final long serialVersionUID = 1L; @ManyToOne(fetch = FetchType.LAZY) @@ -178,23 +177,19 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio } @Override - public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() - .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction))); - + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(this)); } @Override - public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post(new ActionPropertyChangeEvent(jpaAction, - EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent)))); - + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new ActionPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent))); } @Override - public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) { - + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no action deletion } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index afbddbade..cbaed2dbf 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -36,10 +36,10 @@ import javax.persistence.UniqueConstraint; import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; 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.exception.DistributionSetTypeUndefinedException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; 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; @@ -69,11 +69,12 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity - implements DistributionSet, EventAwareEntity { +public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet, EventAwareEntity { private static final long serialVersionUID = 1L; - private static final String COMPLETE = "complete"; + private static final String COMPLETE_PROPERTY = "complete"; + + private static final String DELETED_PROPERTY = "deleted"; @Column(name = "required_migration_step") private boolean requiredMigrationStep; @@ -291,30 +292,30 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity } @Override - public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder - .getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); - + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(this)); } @Override - public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { final Map.Values> changeSet = EntityPropertyChangeHelper .getChangeSet(JpaDistributionSet.class, descriptorEvent); - if (changeSet.containsKey(COMPLETE) && changeSet.get(COMPLETE).getOldValue().equals(false) - && changeSet.get(COMPLETE).getNewValue().equals(true)) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder - .getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); + if (changeSet.containsKey(COMPLETE_PROPERTY) && changeSet.get(COMPLETE_PROPERTY).getOldValue().equals(false) + && changeSet.get(COMPLETE_PROPERTY).getNewValue().equals(true)) { + EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(this)); } + EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(this)); - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder - .getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); - + if (changeSet.containsKey(DELETED_PROPERTY)) { + final Boolean newDeleted = (Boolean) changeSet.get(DELETED_PROPERTY).getNewValue(); + if (newDeleted) { + EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId())); + } + } } @Override - public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new DistributionDeletedEvent(getTenant(), getId())); } - } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java index 57c4d8a69..85395e27b 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRollout.java @@ -28,7 +28,6 @@ import javax.persistence.UniqueConstraint; 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.AfterTransactionCommitExecutorHolder; 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.ActionType; @@ -49,7 +48,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, EventAwareEntity { +public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -203,21 +202,20 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event } @Override - public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + // there is no rollout creation event + } + + @Override + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new RolloutPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(Rollout.class, descriptorEvent))); } @Override - public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post(new RolloutPropertyChangeEvent(jpaRollout, - EntityPropertyChangeHelper.getChangeSet(Rollout.class, descriptorEvent)))); - - } - - @Override - public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) { - + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no rollout deletion event } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java index 0b7a23985..9bb8644f4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaRolloutGroup.java @@ -26,7 +26,6 @@ import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper; import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.model.Rollout; @@ -45,7 +44,7 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup, EventAwareEntity { +public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup, EventAwareEntity { private static final long serialVersionUID = 1L; @@ -242,21 +241,18 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr } @Override - public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + // there is no RolloutGroup created event } @Override - public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() - .afterCommit(() -> EventBusHolder.getInstance().getEventBus() - .post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup, - EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent)))); + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new RolloutGroupPropertyChangeEvent(this, + EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent))); } @Override - public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) { - + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no RolloutGroup deleted event } - } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java index d67d8e9d1..c91247321 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTarget.java @@ -37,8 +37,8 @@ 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.AfterTransactionCommitExecutorHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker; import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder; @@ -69,8 +69,7 @@ import org.springframework.data.domain.Persistable; // exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for // sub entities @SuppressWarnings("squid:S2160") -public class JpaTarget extends AbstractJpaNamedEntity - implements Persistable, Target, EventAwareEntity { +public class JpaTarget extends AbstractJpaNamedEntity implements Persistable, Target, EventAwareEntity { private static final long serialVersionUID = 1L; @Column(name = "controller_id", length = 64) @@ -239,21 +238,17 @@ public class JpaTarget extends AbstractJpaNamedEntity } @Override - public void fireCreateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() - .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget))); + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(this)); } @Override - public void fireUpdateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit() - .afterCommit(() -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget))); - + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(this)); } @Override - public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) { - + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new TargetDeletedEvent(getTenant(), getId())); } - } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index 59cff35c8..3923275df 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -40,7 +40,6 @@ import javax.persistence.Transient; import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException; -import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; 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; @@ -70,7 +69,7 @@ import org.springframework.data.domain.Persistable; @Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") }) @Entity @EntityListeners(EntityPropertyChangeListener.class) -public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { +public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareEntity { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class); @@ -329,17 +328,17 @@ public class JpaTargetInfo implements Persistable, TargetInfo, EventAwareE } @Override - public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + public void fireCreateEvent(final DescriptorEvent descriptorEvent) { // there is no target info created event } @Override - public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( - () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo))); + public void fireUpdateEvent(final DescriptorEvent descriptorEvent) { + EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(this)); } @Override - public void fireDeleteEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) { + public void fireDeleteEvent(final DescriptorEvent descriptorEvent) { + // there is no target info deleted event } } From 60cc2c333c60ac5f6dfd44f67e4702dfc345ab95 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Mon, 1 Aug 2016 15:12:03 +0200 Subject: [PATCH 11/28] Refactored the code for displaying distributions in the deployment view. --- .../jpa/model/JpaDistributionSet.java | 11 ----- .../management/dstable/DistributionTable.java | 44 +++++++++++-------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java index afbddbade..1fddb8837 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaDistributionSet.java @@ -13,7 +13,6 @@ 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; @@ -34,13 +33,11 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; -import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent; import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException; import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException; import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder; -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; @@ -299,14 +296,6 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity @Override public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) { - final Map.Values> changeSet = EntityPropertyChangeHelper - .getChangeSet(JpaDistributionSet.class, descriptorEvent); - if (changeSet.containsKey(COMPLETE) && changeSet.get(COMPLETE).getOldValue().equals(false) - && changeSet.get(COMPLETE).getNewValue().equals(true)) { - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder - .getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet))); - } - AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder .getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet))); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index ff1edafc8..633a5834b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -21,7 +21,6 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; -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.model.DistributionSet; @@ -123,9 +122,6 @@ public class DistributionTable extends AbstractNamedVersionTable) events); - } else if (DistributionCreatedEvent.class.isInstance(firstEvent) - && ((DistributionCreatedEvent) firstEvent).getEntity().isComplete()) { - refreshDistributions(); } } @@ -133,18 +129,28 @@ public class DistributionTable extends AbstractNamedVersionTable visibleItemIds = (List) getVisibleItemIds(); - - // refresh the details tabs only if selected ds is updated - // refresh the details tabs only if selected ds is updated + + + final Boolean dsVisible = visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent(); + + if((ds.isComplete() && !dsVisible) ){ + refreshDistributions(); + } + else if( (!ds.isComplete() && dsVisible)){ + refreshDistributions(); + managementUIState.setLastSelectedDistribution(null); + } + else if(dsVisible){ + UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); + } + final DistributionSetIdName lastSelectedDsIdName = managementUIState.getLastSelectedDsIdName(); + // refresh the details tabs only if selected ds is updated if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { // update table row+details layout eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, ds)); - } else if (visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent()) { - //update the name/version details visible in table - UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); - } + } } /** @@ -261,7 +267,7 @@ public class DistributionTable extends AbstractNamedVersionTable showMetadataDetails(itemId)); @@ -281,7 +287,7 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + private void onDistributionDeleteEvent(final List events) { final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); final List visibleItemIds = (List) getVisibleItemIds(); boolean shouldRefreshDs = false; for (final DistributionDeletedEvent deletedEvent : events) { - Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); - for (Long dsId : distributionSetIDs) { + final Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); + for (final Long dsId : distributionSetIDs) { final DistributionSetIdName targetIdName = new DistributionSetIdName(dsId, null, null); if (visibleItemIds.contains(targetIdName)) { dsContainer.removeItem(targetIdName); From 9c442967f8a66c31ed0d8f6ac1d35a77793a558f Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Mon, 1 Aug 2016 15:14:40 +0200 Subject: [PATCH 12/28] add tests for repository entity events Signed-off-by: Michael Hirsch --- .../event/DistributionDeletedEvent.java | 25 ++- .../jpa/JpaDistributionSetManagement.java | 8 + .../repository/jpa/JpaTargetManagement.java | 7 + .../eventbus/RepositoryEntityEventTest.java | 161 ++++++++++++++++++ .../dstable/DistributionSetTable.java | 48 +++--- .../management/dstable/DistributionTable.java | 55 +++--- 6 files changed, 237 insertions(+), 67 deletions(-) create mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java index 1edfb47ac..7d04ba9c6 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/DistributionDeletedEvent.java @@ -11,27 +11,26 @@ package org.eclipse.hawkbit.repository.eventbus.event; import org.eclipse.hawkbit.eventbus.event.AbstractDistributedEvent; import org.eclipse.hawkbit.repository.model.DistributionSet; - /** - * * Defines the {@link AbstractDistributedEvent} for deletion of {@link DistributionSet}. - - * + * Defines the {@link AbstractDistributedEvent} for deletion of + * {@link DistributionSet}. */ -public class DistributionDeletedEvent extends AbstractDistributedEvent{ - private static final long serialVersionUID = -3308850381757843098L; - final Long[] distributionSetIDs; +public class DistributionDeletedEvent extends AbstractDistributedEvent { + private static final long serialVersionUID = -3308850381757843098L; + private final Long distributionId; + /** * @param tenant * the tenant for this event * @param distributionSetId - * the ID of the target which has been deleted + * the ID of the distribution set which has been deleted */ - public DistributionDeletedEvent(final String tenant, final Long...distributionIds) { + public DistributionDeletedEvent(final String tenant, final Long distributionId) { super(-1, tenant); - this.distributionSetIDs = distributionIds; + this.distributionId = distributionId; } - public Long[] getDistributionSetIDs() { - return distributionSetIDs; - } + public Long getDistributionSetId() { + return distributionId; + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 84c81966f..8842a3507 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -28,6 +28,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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityLockedException; @@ -54,6 +55,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetTag; import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; 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.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -102,6 +104,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Autowired private AfterTransactionCommitExecutor afterCommit; + @Autowired + private TenantAware tenantAware; + @Override public DistributionSet findDistributionSetByIdWithDetails(final Long distid) { return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid)); @@ -193,6 +198,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { // handle the empty list distributionSetRepository.deleteByIdIn(toHardDelete); } + + Arrays.stream(distributionSetIDs) + .forEach(dsId -> eventBus.post(new DistributionDeletedEvent(tenantAware.getCurrentTenant(), dsId))); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 1cd2ffc3c..225c0b4b2 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -29,6 +29,7 @@ import javax.persistence.criteria.Root; 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.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.jpa.configuration.Constants; @@ -48,6 +49,7 @@ import org.eclipse.hawkbit.repository.model.TargetIdName; import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult; 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.data.domain.Page; @@ -94,6 +96,9 @@ public class JpaTargetManagement implements TargetManagement { @Autowired private EventBus eventBus; + @Autowired + private TenantAware tenantAware; + @Autowired private AfterTransactionCommitExecutor afterCommit; @@ -206,6 +211,8 @@ public class JpaTargetManagement implements TargetManagement { targetInfoRepository.deleteByTargetIdIn(targetsForCurrentTenant); targetRepository.deleteByIdIn(targetsForCurrentTenant); } + targetsForCurrentTenant + .forEach(targetId -> eventBus.post(new TargetDeletedEvent(tenantAware.getCurrentTenant(), targetId))); } @Override diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java new file mode 100644 index 000000000..0aa305d52 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/eventbus/RepositoryEntityEventTest.java @@ -0,0 +1,161 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.jpa.eventbus; + +import static org.fest.assertions.Assertions.assertThat; + +import java.net.URI; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.eclipse.hawkbit.eventbus.event.Event; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.DistributionDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent; +import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent; +import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.Target; +import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; +import org.fest.assertions.api.Assertions; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.eventbus.EventBus; +import com.google.common.eventbus.Subscribe; + +import ru.yandex.qatools.allure.annotations.Description; +import ru.yandex.qatools.allure.annotations.Features; +import ru.yandex.qatools.allure.annotations.Stories; + +@Features("Component Tests - Repository") +@Stories("Entity Events") +public class RepositoryEntityEventTest extends AbstractJpaIntegrationTest { + + @Autowired + private EventBus eventBus; + + private final MyEventListener eventListener = new MyEventListener(); + + @Before + public void beforeTest() { + eventListener.queue.clear(); + eventBus.register(eventListener); + } + + @Test + @Description("Verifies that the target created event is published when a target has been created") + public void targetCreatedEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + + final TargetCreatedEvent targetCreatedEvent = eventListener.waitForEvent(TargetCreatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetCreatedEvent).isNotNull(); + assertThat(targetCreatedEvent.getEntity().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target update event is published when a target has been updated") + public void targetUpdateEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + createdTarget.setName("updateName"); + targetManagement.updateTarget(createdTarget); + + final TargetUpdatedEvent targetUpdatedEvent = eventListener.waitForEvent(TargetUpdatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetUpdatedEvent).isNotNull(); + assertThat(targetUpdatedEvent.getEntity().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target info update event is published when a target info has been updated") + public void targetInfoUpdateEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + controllerManagament.updateTargetStatus(createdTarget.getTargetInfo(), TargetUpdateStatus.PENDING, + System.currentTimeMillis(), URI.create("http://127.0.0.1")); + + final TargetInfoUpdateEvent targetInfoUpdatedEvent = eventListener.waitForEvent(TargetInfoUpdateEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetInfoUpdatedEvent).isNotNull(); + assertThat(targetInfoUpdatedEvent.getEntity().getTarget().getId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the target deleted event is published when a target has been deleted") + public void targetDeletedEventIsPublished() throws InterruptedException { + final Target createdTarget = targetManagement.createTarget(entityFactory.generateTarget("12345")); + + targetManagement.deleteTargets(createdTarget.getId()); + + final TargetDeletedEvent targetDeletedEvent = eventListener.waitForEvent(TargetDeletedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(targetDeletedEvent).isNotNull(); + assertThat(targetDeletedEvent.getTargetId()).isEqualTo(createdTarget.getId()); + } + + @Test + @Description("Verifies that the distribution set created event is published when a distribution set has been created") + public void distributionSetCreatedEventIsPublished() throws InterruptedException { + final DistributionSet generateDistributionSet = entityFactory.generateDistributionSet(); + generateDistributionSet.setName("dsEventTest"); + generateDistributionSet.setVersion("1"); + final DistributionSet createDistributionSet = distributionSetManagement + .createDistributionSet(generateDistributionSet); + + final DistributionCreatedEvent dsCreatedEvent = eventListener.waitForEvent(DistributionCreatedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(dsCreatedEvent).isNotNull(); + assertThat(dsCreatedEvent.getEntity().getId()).isEqualTo(createDistributionSet.getId()); + } + + @Test + @Description("Verifies that the distribution set deleted event is published when a distribution set has been deleted") + public void distributionSetDeletedEventIsPublished() throws InterruptedException { + + final DistributionSet generateDistributionSet = entityFactory.generateDistributionSet(); + generateDistributionSet.setName("dsEventTest"); + generateDistributionSet.setVersion("1"); + final DistributionSet createDistributionSet = distributionSetManagement + .createDistributionSet(generateDistributionSet); + + distributionSetManagement.deleteDistributionSet(createDistributionSet); + + final DistributionDeletedEvent dsDeletedEvent = eventListener.waitForEvent(DistributionDeletedEvent.class, 1, + TimeUnit.SECONDS); + assertThat(dsDeletedEvent).isNotNull(); + assertThat(dsDeletedEvent.getDistributionSetId()).isEqualTo(createDistributionSet.getId()); + } + + private class MyEventListener { + + private final BlockingQueue queue = new LinkedBlockingQueue<>(); + + @Subscribe + public void onEvent(final Event event) { + queue.offer(event); + } + + public T waitForEvent(final Class eventType, final long timeout, final TimeUnit timeUnit) + throws InterruptedException { + Event event = null; + while ((event = queue.poll(timeout, timeUnit)) != null) { + if (event.getClass().isAssignableFrom(eventType)) { + return (T) event; + } + } + Assertions.fail("Missing event " + eventType + " within timeout " + timeout + " " + timeUnit); + return null; + } + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index 7946532a3..6bef7a794 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -108,7 +108,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable visibleItemIds = (List) getVisibleItemIds(); // refresh the details tabs only if selected ds is updated @@ -219,10 +219,10 @@ public class DistributionSetTable extends AbstractNamedVersionTable showMetadataDetails(((DistributionSetIdName) itemId).getId())); + manageMetaDataBtn + .addClickListener(event -> showMetadataDetails(((DistributionSetIdName) itemId).getId())); return manageMetaDataBtn; } }); } - @Override protected List getTableVisibleColumns() { @@ -541,7 +541,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable events) { + private void onDistributionDeleteEvent(final List events) { final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); final List visibleItemIds = (List) getVisibleItemIds(); boolean shouldRefreshDs = false; for (final DistributionDeletedEvent deletedEvent : events) { - Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); - for (Long dsId : distributionSetIDs) { - final DistributionSetIdName targetIdName = new DistributionSetIdName(dsId, null, null); - if (visibleItemIds.contains(targetIdName)) { - dsContainer.removeItem(targetIdName); - } else { - shouldRefreshDs = true; - } + final Long distributionSetId = deletedEvent.getDistributionSetId(); + final DistributionSetIdName targetIdName = new DistributionSetIdName(distributionSetId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index ff1edafc8..7609f71ef 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -93,16 +93,16 @@ public class DistributionTable extends AbstractNamedVersionTable) events); } else if (DistributionCreatedEvent.class.isInstance(firstEvent) && ((DistributionCreatedEvent) firstEvent).getEntity().isComplete()) { - refreshDistributions(); - } + refreshDistributions(); + } } @@ -137,12 +137,12 @@ public class DistributionTable extends AbstractNamedVersionTable visibleItemIds = (List) getVisibleItemIds(); // refresh the details tabs only if selected ds is updated - // refresh the details tabs only if selected ds is updated + // refresh the details tabs only if selected ds is updated if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { // update table row+details layout eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, ds)); } else if (visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent()) { - //update the name/version details visible in table + // update the name/version details visible in table UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); } } @@ -261,27 +261,26 @@ public class DistributionTable extends AbstractNamedVersionTable showMetadataDetails(itemId)); - iconLayout.addComponent((Button)getPinButton(itemId)); + iconLayout.addComponent((Button) getPinButton(itemId)); iconLayout.addComponent(manageMetaDataBtn); return iconLayout; } - + }); } - - + private String getNameAndVerion(final Object itemId) { final Item item = getItem(itemId); final String name = (String) item.getItemProperty(SPUILabelDefinitions.VAR_NAME).getValue(); final String version = (String) item.getItemProperty(SPUILabelDefinitions.VAR_VERSION).getValue(); return name + "." + version; } - - private Button createManageMetadataButton(String nameVersionStr) { + + private Button createManageMetadataButton(final String nameVersionStr) { final Button manageMetadataBtn = SPUIComponentProvider.getButton( SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + nameVersionStr, "", "", null, false, FontAwesome.LIST_ALT, SPUIButtonStyleSmallNoBorder.class); @@ -313,9 +312,9 @@ public class DistributionTable extends AbstractNamedVersionTable events) { + private void onDistributionDeleteEvent(final List events) { final LazyQueryContainer dsContainer = (LazyQueryContainer) getContainerDataSource(); final List visibleItemIds = (List) getVisibleItemIds(); boolean shouldRefreshDs = false; for (final DistributionDeletedEvent deletedEvent : events) { - Long[] distributionSetIDs = deletedEvent.getDistributionSetIDs(); - for (Long dsId : distributionSetIDs) { - final DistributionSetIdName targetIdName = new DistributionSetIdName(dsId, null, null); - if (visibleItemIds.contains(targetIdName)) { - dsContainer.removeItem(targetIdName); - } else { - shouldRefreshDs = true; - } + final Long distributionSetId = deletedEvent.getDistributionSetId(); + final DistributionSetIdName targetIdName = new DistributionSetIdName(distributionSetId, null, null); + if (visibleItemIds.contains(targetIdName)) { + dsContainer.removeItem(targetIdName); + } else { + shouldRefreshDs = true; } } From 1bf91372ae63d98a5d5f176ad31c449a2bff1bba Mon Sep 17 00:00:00 2001 From: Gaurav Date: Mon, 1 Aug 2016 17:51:34 +0200 Subject: [PATCH 13/28] Added the javadoc. --- .../repository/jpa/model/EventAwareEntity.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java index 1c6f217c9..95a14a979 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java @@ -12,9 +12,21 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; public interface EventAwareEntity { + /** + * Fired for the Entity creation. + * @param descriptorEvent + */ void fireCreateEvent(DescriptorEvent descriptorEvent); + /** + * Fired for the Entity updation. + * @param descriptorEvent + */ void fireUpdateEvent(DescriptorEvent descriptorEvent); + /** + * Fired for the Entity deletion. + * @param descriptorEvent + */ void fireDeleteEvent(DescriptorEvent descriptorEvent); } From 0854d023fb1654f41146c555bcc9c8fb553fd529 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Tue, 2 Aug 2016 18:32:44 +0200 Subject: [PATCH 14/28] Fixed the code for the create ds for deployment view and fixed the issue for delete metadata(getting optimistic lock exception) --- .../jpa/JpaDistributionSetManagement.java | 11 +++- .../management/dstable/DistributionTable.java | 57 ++++++++++--------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 8842a3507..e8e05a9e1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -483,11 +483,13 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { if (distributionSetMetadataRepository.exists(metadata.getId())) { throwMetadataKeyAlreadyExists(metadata.getId().getKey()); } + + final DistributionSet latestDistributionSet = findDistributionSetById(metadata.getDistributionSet().getId()); // merge base distribution set so optLockRevision gets updated and audit // log written because // modifying metadata is modifying the base distribution set itself for // auditing purposes. - entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L); return distributionSetMetadataRepository.save(metadata); } @@ -502,7 +504,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { for (final JpaDistributionSetMetadata distributionSetMetadata : metadata) { checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId()); } - metadata.forEach(m -> entityManager.merge((JpaDistributionSet) m.getDistributionSet()).setLastModifiedAt(0L)); + metadata.forEach(m -> entityManager.merge((JpaDistributionSet) findDistributionSetById(m.getDistributionSet().getId())).setLastModifiedAt(0L)); return new ArrayList<>( (Collection) distributionSetMetadataRepository.save(metadata)); @@ -518,7 +520,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { findOne(metadata.getDistributionSet(), metadata.getKey()); // touch it to update the lock revision because we are modifying the // DS indirectly - entityManager.merge((JpaDistributionSet) metadata.getDistributionSet()).setLastModifiedAt(0L); + final DistributionSet latestDistributionSet = findDistributionSetById(metadata.getDistributionSet().getId()); + entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L); return distributionSetMetadataRepository.save(metadata); } @@ -526,6 +529,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement { @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) { + final DistributionSet latestDistributionSet = findDistributionSetById(distributionSet.getId()); + entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L); distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key)); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index 3ded0ed07..56fdd9114 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -21,6 +21,7 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.EntityFactory; import org.eclipse.hawkbit.repository.SpPermissionChecker; import org.eclipse.hawkbit.repository.TargetManagement; +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.model.DistributionSet; @@ -92,16 +93,16 @@ public class DistributionTable extends AbstractNamedVersionTable) events); - } + } else if (DistributionCreatedEvent.class.isInstance(firstEvent) + && ((DistributionCreatedEvent) firstEvent).getEntity().isComplete()) { + refreshDistributions(); + } } @EventBusListenerMethod(scope = EventScope.SESSION) void onEvents(final DistributionSetUpdateEvent event) { final DistributionSet ds = event.getEntity(); - + final List visibleItemIds = (List) getVisibleItemIds(); - - - final Boolean dsVisible = visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst().isPresent(); - - if((ds.isComplete() && !dsVisible) ){ + + final Boolean dsVisible = visibleItemIds.stream().filter(e -> e.getId().equals(ds.getId())).findFirst() + .isPresent(); + + if ((ds.isComplete() && !dsVisible)) { refreshDistributions(); - } - else if( (!ds.isComplete() && dsVisible)){ + } else if ((!ds.isComplete() && dsVisible)) { refreshDistributions(); - managementUIState.setLastSelectedDistribution(null); - } - else if(dsVisible){ + if (ds.getId().equals(managementUIState.getLastSelectedDsIdName().getId())) { + managementUIState.setLastSelectedDistribution(null); + managementUIState.setLastSelectedEntity(null); + } + + } else if (dsVisible) { UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); } final DistributionSetIdName lastSelectedDsIdName = managementUIState.getLastSelectedDsIdName(); - // refresh the details tabs only if selected ds is updated + // refresh the details tabs only if selected ds is updated if (lastSelectedDsIdName != null && lastSelectedDsIdName.getId().equals(ds.getId())) { // update table row+details layout eventBus.publish(this, new DistributionTableEvent(BaseEntityEventType.UPDATED_ENTITY, ds)); - } + } } /** @@ -271,22 +277,21 @@ public class DistributionTable extends AbstractNamedVersionTable showMetadataDetails(itemId)); - iconLayout.addComponent((Button)getPinButton(itemId)); + iconLayout.addComponent((Button) getPinButton(itemId)); iconLayout.addComponent(manageMetaDataBtn); return iconLayout; } - + }); } - - + private String getNameAndVerion(final Object itemId) { final Item item = getItem(itemId); final String name = (String) item.getItemProperty(SPUILabelDefinitions.VAR_NAME).getValue(); final String version = (String) item.getItemProperty(SPUILabelDefinitions.VAR_VERSION).getValue(); return name + "." + version; } - + private Button createManageMetadataButton(final String nameVersionStr) { final Button manageMetadataBtn = SPUIComponentProvider.getButton( SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + nameVersionStr, "", "", null, false, @@ -319,9 +324,9 @@ public class DistributionTable extends AbstractNamedVersionTable Date: Mon, 8 Aug 2016 09:14:48 +0200 Subject: [PATCH 15/28] add javadoc Signed-off-by: Michael Hirsch --- .../repository/jpa/model/EntityPropertyChangeListener.java | 3 ++- .../hawkbit/repository/jpa/model/EventAwareEntity.java | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java index 13b1507db..27fbc687e 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EntityPropertyChangeListener.java @@ -13,7 +13,8 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.DescriptorEventAdapter; /** - * Listens to change in property values of an entity. + * Listens to change in property values of an entity and calls the corresponding + * {@link EventAwareEntity}. * */ public class EntityPropertyChangeListener extends DescriptorEventAdapter { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java index 95a14a979..889a61796 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/EventAwareEntity.java @@ -10,22 +10,29 @@ package org.eclipse.hawkbit.repository.jpa.model; import org.eclipse.persistence.descriptors.DescriptorEvent; +/** + * Interfaces which can be implemented by entities to be called when the entity + * should fire an event because the entity has been created, updated or deleted. + */ public interface EventAwareEntity { /** * Fired for the Entity creation. + * * @param descriptorEvent */ void fireCreateEvent(DescriptorEvent descriptorEvent); /** * Fired for the Entity updation. + * * @param descriptorEvent */ void fireUpdateEvent(DescriptorEvent descriptorEvent); /** * Fired for the Entity deletion. + * * @param descriptorEvent */ void fireDeleteEvent(DescriptorEvent descriptorEvent); From 8fa2a60a7177cc3801382b755b0af5faa0aec082 Mon Sep 17 00:00:00 2001 From: Gaurav Date: Mon, 8 Aug 2016 13:30:16 +0200 Subject: [PATCH 16/28] Formatted the code. Signed-off-by: Gaurav --- .../eventbus/event/TargetUpdatedEvent.java | 18 ++++---- .../jpa/model/DescriptorEventDetails.java | 44 ++++++++++--------- .../helper/EntityPropertyChangeHelper.java | 25 ++++------- 3 files changed, 42 insertions(+), 45 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java index 4896f4ca8..8ae5718e9 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/eventbus/event/TargetUpdatedEvent.java @@ -16,14 +16,16 @@ import org.eclipse.hawkbit.repository.model.Target; */ public class TargetUpdatedEvent extends AbstractBaseEntityEvent { - private static final long serialVersionUID = 5665118668865832477L; + private static final long serialVersionUID = 5665118668865832477L; - /** - * Constructor - * @param baseEntity Target entity - */ - public TargetUpdatedEvent(final Target baseEntity) { - super(baseEntity); - } + /** + * Constructor + * + * @param baseEntity + * Target entity + */ + public TargetUpdatedEvent(final Target baseEntity) { + super(baseEntity); + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java index a80891604..091b2eb77 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java @@ -17,31 +17,33 @@ import org.eclipse.persistence.descriptors.DescriptorEvent; */ public class DescriptorEventDetails { - enum ActionType { - CREATE, UPDATE; - } + enum ActionType { + CREATE, UPDATE; + } - private final DescriptorEvent descriptorEvent; + private final DescriptorEvent descriptorEvent; - private final ActionType actiontype; + private final ActionType actiontype; - /** - * Constructor - * @param actionType Action type - * @param descriptorEvent Descriptor Event - */ - public DescriptorEventDetails(final ActionType actionType, - final DescriptorEvent descriptorEvent) { - this.descriptorEvent = descriptorEvent; - this.actiontype = actionType; - } + /** + * Constructor + * + * @param actionType + * Action type + * @param descriptorEvent + * Descriptor Event + */ + public DescriptorEventDetails(final ActionType actionType, final DescriptorEvent descriptorEvent) { + this.descriptorEvent = descriptorEvent; + this.actiontype = actionType; + } - public DescriptorEvent getDescriptorEvent() { - return descriptorEvent; - } + public DescriptorEvent getDescriptorEvent() { + return descriptorEvent; + } - public ActionType getActiontype() { - return actiontype; - } + public ActionType getActiontype() { + return actiontype; + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java index 0697bcead..2be398e24 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/helper/EntityPropertyChangeHelper.java @@ -19,15 +19,15 @@ 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. + * Helper class to get the change set for the property changes in the Entity. * * @param */ -public class EntityPropertyChangeHelper { - - +public class EntityPropertyChangeHelper { + /** * To get the map of entity property change set + * * @param clazz * @param event * @return the map of the changeSet @@ -35,19 +35,12 @@ public class EntityPropertyChangeHelper { public static Map.Values> getChangeSet( final Class clazz, final DescriptorEvent event) { final T rolloutGroup = clazz.cast(event.getObject()); - final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()) - .getObjectChangeSet(); - return changeSet - .getChanges() - .stream() - .filter(record -> record instanceof DirectToFieldChangeRecord) + 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 AbstractPropertyChangeEvent( - rolloutGroup, null).new Values(record - .getOldValue(), record.getNewValue()))); + .collect(Collectors.toMap(record -> record.getAttribute(), + record -> new AbstractPropertyChangeEvent(rolloutGroup, null).new Values( + record.getOldValue(), record.getNewValue()))); } } From 913692f94724449ff6647bdddb074a705ca377e8 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Wed, 10 Aug 2016 09:22:57 +0200 Subject: [PATCH 17/28] lock session on error showing error notification Signed-off-by: Michael Hirsch --- .../hawkbit/ui/components/HawkbitUIErrorHandler.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 7729b72a4..bd56aba42 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -21,6 +21,7 @@ import com.google.common.base.Optional; import com.vaadin.server.DefaultErrorHandler; import com.vaadin.server.ErrorEvent; import com.vaadin.server.Page; +import com.vaadin.server.VaadinSession; import com.vaadin.ui.Component; /** @@ -40,7 +41,13 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { if (originError.isPresent()) { final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); - message.show(originError.get()); + final VaadinSession current = VaadinSession.getCurrent(); + current.lock(); + try { + message.show(originError.get()); + } finally { + current.unlock(); + } } } From 9cc63ce1281e8f7818a6e9ad4ab803b2af789478 Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 13:25:24 +0200 Subject: [PATCH 18/28] Refactor UI Error Handler. Need to put UI in constructor. So the message is shown in the same browser window. Signed-off-by: Melanie Retter --- .../ui/components/HawkbitUIErrorHandler.java | 24 ++++++++++++++++--- .../targettable/BulkUploadHandler.java | 9 ++++--- .../TargetBulkUpdateWindowLayout.java | 3 ++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 7729b72a4..643d662eb 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -18,10 +18,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; +import com.vaadin.server.ClientConnector.ConnectorErrorEvent; import com.vaadin.server.DefaultErrorHandler; import com.vaadin.server.ErrorEvent; import com.vaadin.server.Page; +import com.vaadin.shared.Connector; +import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; +import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.UI; /** * Default handler for SP UI. @@ -38,10 +43,23 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { final Optional originError = getPageOriginError(event); + final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); + if (originError.isPresent()) { - final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); - message.show(originError.get()); + final Connector connector = ((ConnectorErrorEvent) event).getConnector(); + // in case of BulkUpload + if (connector instanceof UI) { + ((UI) (((ConnectorErrorEvent) event).getConnector())).access(() -> message.show(originError.get())); + return; + } + // Other UI components + if (connector instanceof AbstractComponent) { + ((AbstractComponent) connector).getUI().access(() -> message.show(originError.get())); + return; + } } + // Default + HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), Type.HUMANIZED_MESSAGE); } private static Throwable getRootExceptionFrom(final ErrorEvent event) { @@ -66,7 +84,7 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { return Optional.fromNullable(errorOrigin.getUI().getPage()); } - return Optional.of(Page.getCurrent()); + return Optional.absent(); } protected HawkbitErrorNotificationMessage buildNotification(final Throwable exception) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java index 83082be01..116853afb 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java @@ -100,6 +100,7 @@ public class BulkUploadHandler extends CustomComponent final TargetBulkUpdateWindowLayout targetBulkUpdateWindowLayout; private transient EntityFactory entityFactory; + private final UI uiInstance; /** * @@ -111,8 +112,9 @@ public class BulkUploadHandler extends CustomComponent */ public BulkUploadHandler(final TargetBulkUpdateWindowLayout targetBulkUpdateWindowLayout, final TargetManagement targetManagement, final ManagementUIState managementUIState, - final DeploymentManagement deploymentManagement, final I18N i18n) { + final DeploymentManagement deploymentManagement, final I18N i18n, final UI uiInstance) { this.targetBulkUpdateWindowLayout = targetBulkUpdateWindowLayout; + this.uiInstance = uiInstance; this.comboBox = targetBulkUpdateWindowLayout.getDsNamecomboBox(); this.descTextArea = targetBulkUpdateWindowLayout.getDescTextArea(); this.targetManagement = targetManagement; @@ -213,7 +215,6 @@ public class BulkUploadHandler extends CustomComponent * below event. */ eventBus.publish(this, new TargetTableEvent(TargetComponentEvent.BULK_UPLOAD_PROCESS_STARTED)); - while ((line = reader.readLine()) != null) { innerCounter++; readEachLine(line, innerCounter, totalFileSize); @@ -222,9 +223,7 @@ public class BulkUploadHandler extends CustomComponent } catch (final IOException e) { LOG.error("Error reading file {}", tempFile.getName(), e); } catch (final RuntimeException e) { - if (UI.getCurrent() != null) { - UI.getCurrent().getErrorHandler().error(new com.vaadin.server.ErrorEvent(e)); - } + uiInstance.getErrorHandler().error(new ConnectorErrorEvent(uiInstance, e)); } finally { deleteFile(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java index b77576411..bfc889e7f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java @@ -52,6 +52,7 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Link; import com.vaadin.ui.ProgressBar; import com.vaadin.ui.TextArea; +import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; @@ -174,7 +175,7 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent { private BulkUploadHandler getBulkUploadHandler() { final BulkUploadHandler bulkUploadHandler = new BulkUploadHandler(this, targetManagement, managementUIState, - deploymentManagement, i18n); + deploymentManagement, i18n, UI.getCurrent()); bulkUploadHandler.buildLayout(); bulkUploadHandler.addStyleName(SPUIStyleDefinitions.BULK_UPLOAD_BUTTON); return bulkUploadHandler; From 6205126279ef807ada376a1577a6a52edb1b651b Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 13:54:28 +0200 Subject: [PATCH 19/28] Lock is only needed when BulkUpload Signed-off-by: Melanie Retter --- .../hawkbit/ui/components/HawkbitUIErrorHandler.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 6eb37df3d..dcea17f8a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -23,7 +23,6 @@ import com.vaadin.server.DefaultErrorHandler; import com.vaadin.server.ErrorEvent; import com.vaadin.server.Page; import com.vaadin.shared.Connector; -import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; import com.vaadin.ui.Notification.Type; import com.vaadin.ui.UI; @@ -47,16 +46,14 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { if (originError.isPresent()) { final Connector connector = ((ConnectorErrorEvent) event).getConnector(); - // in case of BulkUpload + // in case of BulkUpload: BulkUpload needs a look to show the + // notification if (connector instanceof UI) { ((UI) (((ConnectorErrorEvent) event).getConnector())).access(() -> message.show(originError.get())); return; } - // Other UI components - if (connector instanceof AbstractComponent) { - ((AbstractComponent) connector).getUI().access(() -> message.show(originError.get())); - return; - } + message.show(originError.get()); + return; } // Default HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), Type.HUMANIZED_MESSAGE); From 4534ece86047da37683781c6747be8f9082e7c0a Mon Sep 17 00:00:00 2001 From: Gaurav Date: Thu, 11 Aug 2016 14:03:40 +0200 Subject: [PATCH 20/28] Fixed the issue of refreshing the tag details section for the distributions. Signed-off-by: Gaurav --- .../hawkbit/ui/distributions/dstable/DistributionSetTable.java | 2 +- .../hawkbit/ui/management/dstable/DistributionTable.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index 3695ef488..6cda2cd16 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -137,7 +137,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable e.getId().equals(ds.getId())).findFirst().isPresent()) { // update the name/version details visible in table UI.getCurrent().access(() -> updateDistributionInTable(event.getEntity())); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index 6e4714e14..e4313dd80 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -155,7 +155,7 @@ public class DistributionTable extends AbstractNamedVersionTable Date: Thu, 11 Aug 2016 14:15:19 +0200 Subject: [PATCH 21/28] Correct typo Signed-off-by: Melanie Retter --- .../eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index dcea17f8a..127063243 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -46,7 +46,7 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { if (originError.isPresent()) { final Connector connector = ((ConnectorErrorEvent) event).getConnector(); - // in case of BulkUpload: BulkUpload needs a look to show the + // in case of BulkUpload: BulkUpload needs a lock to show the // notification if (connector instanceof UI) { ((UI) (((ConnectorErrorEvent) event).getConnector())).access(() -> message.show(originError.get())); From 0d632d598a07a0918197e701cfd3155a43042bd5 Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 14:33:34 +0200 Subject: [PATCH 22/28] Delete empty rows in Java Doc Signed-off-by: Melanie Retter --- .../eclipse/hawkbit/repository/jpa/RolloutManagementTest.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java index b5cc84c9e..a23ada6e6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/RolloutManagementTest.java @@ -56,9 +56,6 @@ import ru.yandex.qatools.allure.annotations.Stories; /** * Junit tests for RolloutManagment. - * - * @author Michael Hirsch - * */ @Features("Component Tests - Repository") @Stories("Rollout Management") @@ -923,7 +920,6 @@ public class RolloutManagementTest extends AbstractJpaIntegrationTest { private void validateStatus(final TotalTargetCountStatus totalTargetCountStatus, final Map expectedTotalCountStates) { - for (final Map.Entry entry : expectedTotalCountStates.entrySet()) { final Long countReady = totalTargetCountStatus.getTotalTargetCountByStatus(entry.getKey()); assertThat(countReady).isEqualTo(entry.getValue()); From 92fb82129acdf5e15ad07a083c8552d9971894c6 Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 16:05:22 +0200 Subject: [PATCH 23/28] Refactoring HawkbitUiErrorHandler Signed-off-by: Melanie Retter --- .../hawkbit/ui/components/HawkbitUIErrorHandler.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 127063243..209e84790 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -46,16 +46,13 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { if (originError.isPresent()) { final Connector connector = ((ConnectorErrorEvent) event).getConnector(); - // in case of BulkUpload: BulkUpload needs a lock to show the - // notification if (connector instanceof UI) { - ((UI) (((ConnectorErrorEvent) event).getConnector())).access(() -> message.show(originError.get())); + ((UI) connector).access(() -> message.show(originError.get())); return; } message.show(originError.get()); return; } - // Default HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), Type.HUMANIZED_MESSAGE); } @@ -86,10 +83,6 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { protected HawkbitErrorNotificationMessage buildNotification(final Throwable exception) { LOG.error("Error in UI: ", exception); - return createHawkbitErrorNotificationMessage(exception); - } - - protected HawkbitErrorNotificationMessage createHawkbitErrorNotificationMessage(final Throwable exception) { final I18N i18n = SpringContextHelper.getBean(I18N.class); return new HawkbitErrorNotificationMessage(STYLE, i18n.get("caption.error"), i18n.get("message.error.temp", exception.getClass().getSimpleName()), false); From 643eb238395c5b9e5df7e8922e6f9ce687ea18d4 Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 16:25:12 +0200 Subject: [PATCH 24/28] Revert method deletion Signed-off-by: Melanie Retter --- .../eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 209e84790..15159cc8c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -83,6 +83,10 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { protected HawkbitErrorNotificationMessage buildNotification(final Throwable exception) { LOG.error("Error in UI: ", exception); + return createHawkbitErrorNotificationMessage(exception); + } + + protected HawkbitErrorNotificationMessage createHawkbitErrorNotificationMessage(final Throwable exception) { final I18N i18n = SpringContextHelper.getBean(I18N.class); return new HawkbitErrorNotificationMessage(STYLE, i18n.get("caption.error"), i18n.get("message.error.temp", exception.getClass().getSimpleName()), false); From c3145bed58885f8675b38e06ac6025dad316cc57 Mon Sep 17 00:00:00 2001 From: Melanie Retter Date: Thu, 11 Aug 2016 17:51:39 +0200 Subject: [PATCH 25/28] Refactor: Log message can be overwritten Signed-off-by: Melanie Retter --- .../ui/components/HawkbitUIErrorHandler.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 15159cc8c..229f85bf5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -61,13 +61,13 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { return getRootCauseOf(event.getThrowable()); } - private static Throwable getRootCauseOf(final Throwable exception) { + private static Throwable getRootCauseOf(final Throwable ex) { - if (exception.getCause() != null) { - return getRootCauseOf(exception.getCause()); + if (ex.getCause() != null) { + return getRootCauseOf(ex.getCause()); } - return exception; + return ex; } private static Optional getPageOriginError(final ErrorEvent event) { @@ -81,15 +81,16 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { return Optional.absent(); } - protected HawkbitErrorNotificationMessage buildNotification(final Throwable exception) { - LOG.error("Error in UI: ", exception); - return createHawkbitErrorNotificationMessage(exception); - } + protected HawkbitErrorNotificationMessage buildNotification(final Throwable ex) { + + log(ex); - protected HawkbitErrorNotificationMessage createHawkbitErrorNotificationMessage(final Throwable exception) { final I18N i18n = SpringContextHelper.getBean(I18N.class); return new HawkbitErrorNotificationMessage(STYLE, i18n.get("caption.error"), - i18n.get("message.error.temp", exception.getClass().getSimpleName()), false); + i18n.get("message.error.temp", ex.getClass().getSimpleName()), false); } + protected void log(final Throwable exception) { + LOG.error("Error in UI: ", exception); + } } From 5d250a03be89f0e3601d2c17ce786e02f6bd1e3f Mon Sep 17 00:00:00 2001 From: Jonathan Philip Knoblauch Date: Fri, 12 Aug 2016 14:28:25 +0200 Subject: [PATCH 26/28] Refactoring for error handler Signed-off-by: Jonathan Philip Knoblauch --- .../ui/components/HawkbitUIErrorHandler.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 229f85bf5..964ed3646 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -41,19 +41,22 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { public void error(final ErrorEvent event) { final Optional originError = getPageOriginError(event); - final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); - if (originError.isPresent()) { + if (!originError.isPresent()) { + HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), + Type.HUMANIZED_MESSAGE); + return; + } + + if (event instanceof ConnectorErrorEvent) { final Connector connector = ((ConnectorErrorEvent) event).getConnector(); if (connector instanceof UI) { ((UI) connector).access(() -> message.show(originError.get())); return; } - message.show(originError.get()); - return; } - HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), Type.HUMANIZED_MESSAGE); + message.show(originError.get()); } private static Throwable getRootExceptionFrom(final ErrorEvent event) { From 971b0aecb6058ce56ded8dac4ac7296c93176e60 Mon Sep 17 00:00:00 2001 From: Jonathan Philip Knoblauch Date: Fri, 12 Aug 2016 16:08:44 +0200 Subject: [PATCH 27/28] Refactoring error handler Signed-off-by: Jonathan Philip Knoblauch --- .../ui/components/HawkbitUIErrorHandler.java | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java index 964ed3646..cdbd04034 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitUIErrorHandler.java @@ -40,27 +40,26 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { @Override public void error(final ErrorEvent event) { - final Optional originError = getPageOriginError(event); final HawkbitErrorNotificationMessage message = buildNotification(getRootExceptionFrom(event)); - - if (!originError.isPresent()) { - HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), - Type.HUMANIZED_MESSAGE); - return; - } - if (event instanceof ConnectorErrorEvent) { final Connector connector = ((ConnectorErrorEvent) event).getConnector(); if (connector instanceof UI) { - ((UI) connector).access(() -> message.show(originError.get())); + final UI uiInstance = (UI) connector; + uiInstance.access(() -> message.show(uiInstance.getPage())); return; } } - message.show(originError.get()); + + final Optional originError = getPageOriginError(event); + if (originError.isPresent()) { + message.show(originError.get()); + return; + } + + HawkbitErrorNotificationMessage.show(message.getCaption(), message.getDescription(), Type.HUMANIZED_MESSAGE); } private static Throwable getRootExceptionFrom(final ErrorEvent event) { - return getRootCauseOf(event.getThrowable()); } @@ -84,16 +83,18 @@ public class HawkbitUIErrorHandler extends DefaultErrorHandler { return Optional.absent(); } + /** + * Method to build a notification based on an exception. + * + * @param ex + * the throwable + * @return a hawkbit error notification message + */ protected HawkbitErrorNotificationMessage buildNotification(final Throwable ex) { - - log(ex); - + LOG.error("Error in UI: ", ex); final I18N i18n = SpringContextHelper.getBean(I18N.class); return new HawkbitErrorNotificationMessage(STYLE, i18n.get("caption.error"), i18n.get("message.error.temp", ex.getClass().getSimpleName()), false); } - protected void log(final Throwable exception) { - LOG.error("Error in UI: ", exception); - } } From 79e0cccfa9ebe85c84b3905941f57e957d86cf88 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Tue, 16 Aug 2016 12:29:14 +0200 Subject: [PATCH 28/28] remove not used class Signed-off-by: Michael Hirsch --- .../jpa/model/DescriptorEventDetails.java | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java deleted file mode 100644 index 091b2eb77..000000000 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/DescriptorEventDetails.java +++ /dev/null @@ -1,49 +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 org.eclipse.persistence.descriptors.DescriptorEvent; - -/** - * - * Holds details of action(Create/Update) and @link{DescriptorEvent}. - * - */ -public class DescriptorEventDetails { - - enum ActionType { - CREATE, UPDATE; - } - - private final DescriptorEvent descriptorEvent; - - private final ActionType actiontype; - - /** - * Constructor - * - * @param actionType - * Action type - * @param descriptorEvent - * Descriptor Event - */ - public DescriptorEventDetails(final ActionType actionType, final DescriptorEvent descriptorEvent) { - this.descriptorEvent = descriptorEvent; - this.actiontype = actionType; - } - - public DescriptorEvent getDescriptorEvent() { - return descriptorEvent; - } - - public ActionType getActiontype() { - return actiontype; - } - -}