Remove TargetInfo entity (#453)
Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -321,8 +321,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* rolloutgroup in a specific status
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
Page<Action> findByRolloutAndRolloutGroupParentAndStatus(Pageable pageable, JpaRollout rollout,
|
||||
JpaRolloutGroup rolloutGroupParent, Status actionStatus);
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIdAndStatus(Pageable pageable, Long rollout,
|
||||
Long rolloutGroupParent, Status actionStatus);
|
||||
|
||||
/**
|
||||
* Retrieving all actions referring to the first group of a rollout.
|
||||
@@ -337,7 +337,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* rolloutgroup in a specific status
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
Page<Action> findByRolloutAndRolloutGroupParentIsNullAndStatus(Pageable pageable, JpaRollout rollout,
|
||||
Page<Action> findByRolloutIdAndRolloutGroupParentIsNullAndStatus(Pageable pageable, Long rollout,
|
||||
Status actionStatus);
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,12 +11,10 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
@@ -41,24 +39,19 @@ public final class DeploymentHelper {
|
||||
* of the target
|
||||
* @param setInstalledDate
|
||||
* to set
|
||||
* @param entityManager
|
||||
* for the operation
|
||||
* @param targetInfoRepository
|
||||
* for the operation
|
||||
*
|
||||
* @return updated target
|
||||
*/
|
||||
static JpaTarget updateTargetInfo(@NotNull final JpaTarget target, @NotNull final TargetUpdateStatus status,
|
||||
final boolean setInstalledDate, final TargetInfoRepository targetInfoRepository,
|
||||
final EntityManager entityManager) {
|
||||
final JpaTargetInfo ts = (JpaTargetInfo) target.getTargetInfo();
|
||||
ts.setUpdateStatus(status);
|
||||
final boolean setInstalledDate) {
|
||||
target.setUpdateStatus(status);
|
||||
|
||||
if (setInstalledDate) {
|
||||
ts.setInstallationDate(System.currentTimeMillis());
|
||||
target.setInstallationDate(System.currentTimeMillis());
|
||||
}
|
||||
targetInfoRepository.save(ts);
|
||||
return entityManager.merge(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,14 +65,11 @@ public final class DeploymentHelper {
|
||||
* for the operation
|
||||
* @param targetRepository
|
||||
* for the operation
|
||||
* @param entityManager
|
||||
* for the operation
|
||||
* @param targetInfoRepository
|
||||
* for the operation
|
||||
*/
|
||||
static void successCancellation(final JpaAction action, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final TargetInfoRepository targetInfoRepository,
|
||||
final EntityManager entityManager) {
|
||||
final TargetRepository targetRepository) {
|
||||
|
||||
// set action inactive
|
||||
action.setActive(false);
|
||||
@@ -90,12 +80,11 @@ public final class DeploymentHelper {
|
||||
.filter(a -> !a.getId().equals(action.getId())).collect(Collectors.toList());
|
||||
|
||||
if (nextActiveActions.isEmpty()) {
|
||||
target.setAssignedDistributionSet(target.getTargetInfo().getInstalledDistributionSet());
|
||||
updateTargetInfo(target, TargetUpdateStatus.IN_SYNC, false, targetInfoRepository, entityManager);
|
||||
target.setAssignedDistributionSet(target.getInstalledDistributionSet());
|
||||
updateTargetInfo(target, TargetUpdateStatus.IN_SYNC, false);
|
||||
} else {
|
||||
target.setAssignedDistributionSet(nextActiveActions.get(0).getDistributionSet());
|
||||
}
|
||||
target.setNew(false);
|
||||
targetRepository.save(target);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -109,6 +110,12 @@ public interface DistributionSetRepository
|
||||
@Query("select DISTINCT d from JpaDistributionSet d join fetch d.modules m join d.actions a where a.id = :action")
|
||||
JpaDistributionSet findByActionId(@Param("action") Long action);
|
||||
|
||||
@Query("select DISTINCT ds from JpaDistributionSet ds join fetch ds.modules join ds.assignedToTargets t where t.controllerId = :controllerId")
|
||||
Optional<DistributionSet> findAssignedToTarget(@Param("controllerId") String controllerId);
|
||||
|
||||
@Query("select DISTINCT ds from JpaDistributionSet ds join fetch ds.modules join ds.installedAtTargets t where t.controllerId = :controllerId")
|
||||
Optional<DistributionSet> findInstalledAtTarget(@Param("controllerId") String controllerId);
|
||||
|
||||
/**
|
||||
* Counts {@link DistributionSet} instances of given type in the repository.
|
||||
*
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Custom repository implementation as standard spring repository fails as of
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=415027 .
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
|
||||
public class EclipseLinkTargetInfoRepository implements TargetInfoRepository {
|
||||
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
public void setTargetUpdateStatus(final TargetUpdateStatus status, final List<Long> targets) {
|
||||
final Query query = entityManager.createQuery(
|
||||
"update JpaTargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status");
|
||||
query.setParameter("targets", targets);
|
||||
query.setParameter("status", status);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
public <S extends JpaTargetInfo> S save(final S entity) {
|
||||
|
||||
if (entity.isNew()) {
|
||||
entityManager.persist(entity);
|
||||
return entity;
|
||||
} else {
|
||||
return entityManager.merge(entity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException;
|
||||
@@ -40,7 +39,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -48,7 +46,6 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
@@ -92,9 +89,6 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
@Autowired
|
||||
private TargetManagement targetManagement;
|
||||
|
||||
@Autowired
|
||||
private TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private ActionStatusRepository actionStatusRepository;
|
||||
|
||||
@@ -135,10 +129,10 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
public Target updateLastTargetQuery(final String controllerId, final URI address) {
|
||||
final Target target = targetRepository.findByControllerId(controllerId)
|
||||
final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
|
||||
return updateTargetStatus(target.getTargetInfo(), null, System.currentTimeMillis(), address).getTarget();
|
||||
return updateTargetStatus(target, null, System.currentTimeMillis(), address);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,32 +216,29 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
return result;
|
||||
}
|
||||
|
||||
return updateTargetStatus(target.getTargetInfo(), null, System.currentTimeMillis(), address).getTarget();
|
||||
return updateTargetStatus(target, null, System.currentTimeMillis(), address);
|
||||
}
|
||||
|
||||
private TargetInfo updateTargetStatus(final TargetInfo targetInfo, final TargetUpdateStatus status,
|
||||
private Target updateTargetStatus(final JpaTarget toUpdate, final TargetUpdateStatus status,
|
||||
final Long lastTargetQuery, final URI address) {
|
||||
final JpaTargetInfo mtargetInfo = (JpaTargetInfo) entityManager.merge(targetInfo);
|
||||
if (status != null) {
|
||||
mtargetInfo.setUpdateStatus(status);
|
||||
toUpdate.setUpdateStatus(status);
|
||||
}
|
||||
if (lastTargetQuery != null) {
|
||||
mtargetInfo.setLastTargetQuery(lastTargetQuery);
|
||||
toUpdate.setLastTargetQuery(lastTargetQuery);
|
||||
}
|
||||
|
||||
if (mtargetInfo.getUpdateStatus() == TargetUpdateStatus.UNKNOWN) {
|
||||
mtargetInfo.setUpdateStatus(TargetUpdateStatus.REGISTERED);
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new TargetUpdatedEvent(mtargetInfo.getTarget(), applicationContext.getId())));
|
||||
if (TargetUpdateStatus.UNKNOWN.equals(toUpdate.getUpdateStatus())) {
|
||||
toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED);
|
||||
}
|
||||
|
||||
if (address != null) {
|
||||
mtargetInfo.setAddress(address.toString());
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new TargetPollEvent(mtargetInfo.getTarget(), applicationContext.getId())));
|
||||
toUpdate.setAddress(address.toString());
|
||||
afterCommit.afterCommit(
|
||||
() -> eventPublisher.publishEvent(new TargetPollEvent(toUpdate, applicationContext.getId())));
|
||||
}
|
||||
|
||||
return targetInfoRepository.save(mtargetInfo);
|
||||
return targetRepository.save(toUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,8 +282,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
// the canceled action itself.
|
||||
actionStatus.addMessage(
|
||||
RepositoryConstants.SERVER_MESSAGE_PREFIX + "Cancellation completion is finished sucessfully.");
|
||||
DeploymentHelper.successCancellation(action, actionRepository, targetRepository, targetInfoRepository,
|
||||
entityManager);
|
||||
DeploymentHelper.successCancellation(action, actionRepository, targetRepository);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -332,8 +322,7 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
|
||||
switch (actionStatus.getStatus()) {
|
||||
case ERROR:
|
||||
target = DeploymentHelper.updateTargetInfo(target, TargetUpdateStatus.ERROR, false, targetInfoRepository,
|
||||
entityManager);
|
||||
target = DeploymentHelper.updateTargetInfo(target, TargetUpdateStatus.ERROR, false);
|
||||
handleErrorOnAction(action, target);
|
||||
break;
|
||||
case FINISHED:
|
||||
@@ -358,7 +347,6 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
mergedAction.setStatus(Status.ERROR);
|
||||
mergedTarget.setAssignedDistributionSet(null);
|
||||
|
||||
mergedTarget.setNew(false);
|
||||
targetRepository.save(mergedTarget);
|
||||
}
|
||||
|
||||
@@ -380,23 +368,19 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
private void handleFinishedAndStoreInTargetStatus(final JpaTarget target, final JpaAction action) {
|
||||
action.setActive(false);
|
||||
action.setStatus(Status.FINISHED);
|
||||
final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo();
|
||||
final JpaDistributionSet ds = (JpaDistributionSet) entityManager.merge(action.getDistributionSet());
|
||||
|
||||
targetInfo.setInstalledDistributionSet(ds);
|
||||
targetInfo.setInstallationDate(System.currentTimeMillis());
|
||||
target.setInstalledDistributionSet(ds);
|
||||
target.setInstallationDate(System.currentTimeMillis());
|
||||
|
||||
// check if the assigned set is equal to the installed set (not
|
||||
// necessarily the case as another update might be pending already).
|
||||
if (target.getAssignedDistributionSet() != null && target.getAssignedDistributionSet().getId()
|
||||
.equals(targetInfo.getInstalledDistributionSet().getId())) {
|
||||
targetInfo.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||
if (target.getAssignedDistributionSet() != null
|
||||
&& target.getAssignedDistributionSet().getId().equals(target.getInstalledDistributionSet().getId())) {
|
||||
target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||
}
|
||||
|
||||
targetInfoRepository.save(targetInfo);
|
||||
|
||||
afterCommit.afterCommit(
|
||||
() -> eventPublisher.publishEvent(new TargetUpdatedEvent(target, applicationContext.getId())));
|
||||
targetRepository.save(target);
|
||||
|
||||
entityManager.detach(ds);
|
||||
}
|
||||
@@ -408,26 +392,19 @@ public class JpaControllerManagement implements ControllerManagement {
|
||||
final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(controllerId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
|
||||
final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo();
|
||||
targetInfo.getControllerAttributes().putAll(data);
|
||||
target.getControllerAttributes().putAll(data);
|
||||
|
||||
if (targetInfo.getControllerAttributes().size() > securityProperties.getDos()
|
||||
.getMaxAttributeEntriesPerTarget()) {
|
||||
if (target.getControllerAttributes().size() > securityProperties.getDos().getMaxAttributeEntriesPerTarget()) {
|
||||
LOG_DOS.info("Target tries to insert more than the allowed number of entries ({}). DOS attack anticipated!",
|
||||
securityProperties.getDos().getMaxAttributeEntriesPerTarget());
|
||||
throw new ToManyAttributeEntriesException(
|
||||
String.valueOf(securityProperties.getDos().getMaxAttributeEntriesPerTarget()));
|
||||
}
|
||||
|
||||
targetInfo.setLastTargetQuery(System.currentTimeMillis());
|
||||
targetInfo.setRequestControllerAttributes(false);
|
||||
target.setLastTargetQuery(System.currentTimeMillis());
|
||||
target.setRequestControllerAttributes(false);
|
||||
|
||||
final Target result = targetInfoRepository.save(targetInfo).getTarget();
|
||||
|
||||
afterCommit.afterCommit(
|
||||
() -> eventPublisher.publishEvent(new TargetUpdatedEvent(result, applicationContext.getId())));
|
||||
|
||||
return result;
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
@@ -63,8 +62,6 @@ import org.eclipse.hawkbit.repository.model.ActionWithStatusCount;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
@@ -125,9 +122,6 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
@Autowired
|
||||
private TargetManagement targetManagement;
|
||||
|
||||
@Autowired
|
||||
private TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private AuditorAware<String> auditorProvider;
|
||||
|
||||
@@ -257,9 +251,8 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
currentUser = null;
|
||||
}
|
||||
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSet(set, System.currentTimeMillis(),
|
||||
currentUser, tIds));
|
||||
targetIds.forEach(tIds -> targetInfoRepository.setTargetUpdateStatus(TargetUpdateStatus.PENDING, tIds));
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||
set, System.currentTimeMillis(), currentUser, tIds));
|
||||
final Map<String, JpaAction> targetIdsToActions = targets.stream().map(
|
||||
t -> actionRepository.save(createTargetAction(targetsWithActionMap, t, set, rollout, rolloutGroup)))
|
||||
.collect(Collectors.toMap(a -> a.getTarget().getControllerId(), Function.identity()));
|
||||
@@ -311,10 +304,15 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
}
|
||||
|
||||
private void assignDistributionSetEvent(final Action action) {
|
||||
((JpaTargetInfo) action.getTarget().getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new TargetUpdatedEvent(action.getTarget(), applicationContext.getId())));
|
||||
// Update is not available in the object as the update was executed
|
||||
// through JQL
|
||||
final JpaTarget target = (JpaTarget) action.getTarget();
|
||||
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
entityManager.detach(target);
|
||||
|
||||
afterCommit.afterCommit(
|
||||
() -> eventPublisher.publishEvent(new TargetUpdatedEvent(target, applicationContext.getId())));
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new TargetAssignDistributionSetEvent(action, applicationContext.getId())));
|
||||
}
|
||||
@@ -388,15 +386,10 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
* the action id of the assignment
|
||||
*/
|
||||
private void cancelAssignDistributionSetEvent(final Target target, final Long actionId) {
|
||||
loadLazyTargetInfo(target);
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new CancelTargetAssignmentEvent(target, actionId, applicationContext.getId())));
|
||||
}
|
||||
|
||||
private static void loadLazyTargetInfo(final Target target) {
|
||||
target.getTargetInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
@@ -419,8 +412,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
actionStatusRepository.save(new JpaActionStatus(action, Status.CANCELED, System.currentTimeMillis(),
|
||||
"A force quit has been performed."));
|
||||
|
||||
DeploymentHelper.successCancellation(action, actionRepository, targetRepository, targetInfoRepository,
|
||||
entityManager);
|
||||
DeploymentHelper.successCancellation(action, actionRepository, targetRepository);
|
||||
|
||||
return actionRepository.save(action);
|
||||
}
|
||||
@@ -428,29 +420,29 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
public long startScheduledActionsByRolloutGroupParent(@NotNull final Rollout rollout,
|
||||
final RolloutGroup rolloutGroupParent) {
|
||||
public long startScheduledActionsByRolloutGroupParent(@NotNull final Long rolloutId,
|
||||
final Long rolloutGroupParentId) {
|
||||
long totalActionsCount = 0L;
|
||||
long lastStartedActionsCount;
|
||||
do {
|
||||
lastStartedActionsCount = startScheduledActionsByRolloutGroupParentInNewTransaction(rollout,
|
||||
rolloutGroupParent, ACTION_PAGE_LIMIT);
|
||||
lastStartedActionsCount = startScheduledActionsByRolloutGroupParentInNewTransaction(rolloutId,
|
||||
rolloutGroupParentId, ACTION_PAGE_LIMIT);
|
||||
totalActionsCount += lastStartedActionsCount;
|
||||
} while (lastStartedActionsCount > 0);
|
||||
|
||||
return totalActionsCount;
|
||||
}
|
||||
|
||||
private long startScheduledActionsByRolloutGroupParentInNewTransaction(final Rollout rollout,
|
||||
final RolloutGroup rolloutGroupParent, final int limit) {
|
||||
private long startScheduledActionsByRolloutGroupParentInNewTransaction(final Long rolloutId,
|
||||
final Long rolloutGroupParentId, final int limit) {
|
||||
final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setName("startScheduledActions");
|
||||
def.setReadOnly(false);
|
||||
def.setIsolationLevel(Isolation.READ_UNCOMMITTED.value());
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
return new TransactionTemplate(txManager, def).execute(status -> {
|
||||
final Page<Action> rolloutGroupActions = findActionsByRolloutAndRolloutGroupParent(rollout,
|
||||
rolloutGroupParent, limit);
|
||||
final Page<Action> rolloutGroupActions = findActionsByRolloutAndRolloutGroupParent(rolloutId,
|
||||
rolloutGroupParentId, limit);
|
||||
|
||||
rolloutGroupActions.map(action -> (JpaAction) action).forEach(this::startScheduledAction);
|
||||
|
||||
@@ -458,33 +450,35 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
});
|
||||
}
|
||||
|
||||
private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Rollout rollout,
|
||||
final RolloutGroup rolloutGroupParent, final int limit) {
|
||||
final JpaRollout jpaRollout = (JpaRollout) rollout;
|
||||
final JpaRolloutGroup jpaRolloutGroup = (JpaRolloutGroup) rolloutGroupParent;
|
||||
private Page<Action> findActionsByRolloutAndRolloutGroupParent(final Long rolloutId,
|
||||
final Long rolloutGroupParentId, final int limit) {
|
||||
|
||||
final PageRequest pageRequest = new PageRequest(0, limit);
|
||||
if (rolloutGroupParent == null) {
|
||||
return actionRepository.findByRolloutAndRolloutGroupParentIsNullAndStatus(pageRequest, jpaRollout,
|
||||
if (rolloutGroupParentId == null) {
|
||||
return actionRepository.findByRolloutIdAndRolloutGroupParentIsNullAndStatus(pageRequest, rolloutId,
|
||||
Action.Status.SCHEDULED);
|
||||
} else {
|
||||
return actionRepository.findByRolloutAndRolloutGroupParentAndStatus(pageRequest, jpaRollout,
|
||||
jpaRolloutGroup, Action.Status.SCHEDULED);
|
||||
return actionRepository.findByRolloutIdAndRolloutGroupParentIdAndStatus(pageRequest, rolloutId,
|
||||
rolloutGroupParentId, Action.Status.SCHEDULED);
|
||||
}
|
||||
}
|
||||
|
||||
private Action startScheduledAction(final JpaAction action) {
|
||||
private void startScheduledAction(final JpaAction action) {
|
||||
// check if we need to override running update actions
|
||||
final Set<Long> overrideObsoleteUpdateActions = overrideObsoleteUpdateActions(
|
||||
Collections.singletonList(action.getTarget().getId()));
|
||||
|
||||
if (action.getTarget().getAssignedDistributionSet() != null && action.getDistributionSet().getId()
|
||||
.equals(action.getTarget().getAssignedDistributionSet().getId())) {
|
||||
JpaTarget target = (JpaTarget) action.getTarget();
|
||||
|
||||
if (target.getAssignedDistributionSet() != null
|
||||
&& action.getDistributionSet().getId().equals(target.getAssignedDistributionSet().getId())) {
|
||||
// the target has already the distribution set assigned, we don't
|
||||
// need to start the scheduled action, just finish it.
|
||||
action.setStatus(Status.FINISHED);
|
||||
action.setActive(false);
|
||||
setSkipActionStatus(action);
|
||||
return actionRepository.save(action);
|
||||
actionRepository.save(action);
|
||||
return;
|
||||
}
|
||||
|
||||
action.setActive(true);
|
||||
@@ -493,20 +487,18 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
|
||||
setRunningActionStatus(savedAction, null);
|
||||
|
||||
final JpaTarget target = (JpaTarget) savedAction.getTarget();
|
||||
target = (JpaTarget) entityManager.merge(savedAction.getTarget());
|
||||
|
||||
target.setAssignedDistributionSet(savedAction.getDistributionSet());
|
||||
final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo();
|
||||
targetInfo.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
targetRepository.save(target);
|
||||
targetInfoRepository.save(targetInfo);
|
||||
|
||||
// in case we canceled an action before for this target, then don't fire
|
||||
// assignment event
|
||||
if (!overrideObsoleteUpdateActions.contains(savedAction.getId())) {
|
||||
assignDistributionSetEvent(savedAction);
|
||||
afterCommit.afterCommit(() -> eventPublisher
|
||||
.publishEvent(new TargetAssignDistributionSetEvent(savedAction, applicationContext.getId())));
|
||||
}
|
||||
return savedAction;
|
||||
}
|
||||
|
||||
private void setRunningActionStatus(final JpaAction action, final String actionMessage) {
|
||||
@@ -682,4 +674,18 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
public Slice<Action> findActionsAll(final Pageable pageable) {
|
||||
return convertAcPage(actionRepository.findAll(pageable), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
||||
throwExceptionIfTargetFoesNotExist(controllerId);
|
||||
|
||||
return distributoinSetRepository.findAssignedToTarget(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
||||
throwExceptionIfTargetFoesNotExist(controllerId);
|
||||
|
||||
return distributoinSetRepository.findInstalledAtTarget(controllerId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -675,7 +675,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
final JpaDistributionSet result = entityManager.merge((JpaDistributionSet) ds);
|
||||
result.setLastModifiedAt(0L);
|
||||
|
||||
return result;
|
||||
return distributionSetRepository.save(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,6 @@ import javax.persistence.Query;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Root;
|
||||
@@ -33,8 +32,6 @@ import org.eclipse.hawkbit.repository.ReportManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.report.model.DataReportSeries;
|
||||
@@ -85,19 +82,18 @@ public class JpaReportManagement implements ReportManagement {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfo = targetRoot.join(JpaTarget_.targetInfo);
|
||||
final Expression<Long> countColumn = cb.count(targetInfo.get(JpaTargetInfo_.targetId));
|
||||
final Expression<Long> countColumn = cb.count(targetRoot.get(JpaTarget_.id));
|
||||
final CriteriaQuery<Object[]> multiselect = query
|
||||
.multiselect(targetInfo.get(JpaTargetInfo_.updateStatus), countColumn)
|
||||
.groupBy(targetInfo.get(JpaTargetInfo_.updateStatus))
|
||||
.orderBy(cb.desc(targetInfo.get(JpaTargetInfo_.updateStatus)));
|
||||
.multiselect(targetRoot.get(JpaTarget_.updateStatus), countColumn)
|
||||
.groupBy(targetRoot.get(JpaTarget_.updateStatus))
|
||||
.orderBy(cb.desc(targetRoot.get(JpaTarget_.updateStatus)));
|
||||
|
||||
// | col1 | col2 |
|
||||
// | U_STATUS | COUNT |
|
||||
final List<Object[]> resultList = entityManager.createQuery(multiselect).getResultList();
|
||||
|
||||
final List<DataReportSeriesItem<TargetUpdateStatus>> reportSeriesItems = resultList.stream()
|
||||
.map(r -> new DataReportSeriesItem<TargetUpdateStatus>((TargetUpdateStatus) r[0], (Long) r[1]))
|
||||
.map(r -> new DataReportSeriesItem<>((TargetUpdateStatus) r[0], (Long) r[1]))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new DataReportSeries<>("Target Status Overview", reportSeriesItems);
|
||||
@@ -117,25 +113,25 @@ public class JpaReportManagement implements ReportManagement {
|
||||
final List<DataReportSeriesItem<SeriesTime>> resultList = new ArrayList<>();
|
||||
|
||||
// hours
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.HOUR,
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.HOUR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, beforeHour, now)).getSingleResult()));
|
||||
// days
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.DAY, entityManager
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.DAY, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeDay, beforeHour)).getSingleResult()));
|
||||
// weeks
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.WEEK, entityManager
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.WEEK, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeWeek, beforeDay)).getSingleResult()));
|
||||
// months
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MONTH, entityManager
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.MONTH, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeMonth, beforeWeek)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.YEAR, entityManager
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.YEAR, entityManager
|
||||
.createQuery(createCountSelectTargetsLastPoll(cb, beforeYear, beforeMonth)).getSingleResult()));
|
||||
// years
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.MORE_THAN_YEAR,
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.MORE_THAN_YEAR,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, beforeYear)).getSingleResult()));
|
||||
// never
|
||||
resultList.add(new DataReportSeriesItem<SeriesTime>(SeriesTime.NEVER,
|
||||
resultList.add(new DataReportSeriesItem<>(SeriesTime.NEVER,
|
||||
entityManager.createQuery(createCountSelectTargetsLastPoll(cb, null, null)).getSingleResult()));
|
||||
|
||||
return new DataReportSeries<>("TargetLastPoll", resultList);
|
||||
@@ -172,8 +168,8 @@ public class JpaReportManagement implements ReportManagement {
|
||||
final CriteriaBuilder cbTopX = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> queryTopX = cbTopX.createQuery(Object[].class);
|
||||
final Root<JpaDistributionSet> rootTopX = queryTopX.from(JpaDistributionSet.class);
|
||||
final ListJoin<JpaDistributionSet, JpaTargetInfo> joinTopX = rootTopX
|
||||
.join(JpaDistributionSet_.installedAtTargets, JoinType.LEFT);
|
||||
final ListJoin<JpaDistributionSet, JpaTarget> joinTopX = rootTopX.join(JpaDistributionSet_.installedAtTargets,
|
||||
JoinType.LEFT);
|
||||
final Expression<Long> countColumn = cbTopX.count(joinTopX);
|
||||
// top x usage query
|
||||
final CriteriaQuery<Object[]> groupBy = queryTopX
|
||||
@@ -270,14 +266,13 @@ public class JpaReportManagement implements ReportManagement {
|
||||
// count select statement
|
||||
final CriteriaQuery<Long> countSelect = cb.createQuery(Long.class);
|
||||
final Root<JpaTarget> countSelectRoot = countSelect.from(JpaTarget.class);
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = countSelectRoot.join(JpaTarget_.targetInfo);
|
||||
countSelect.select(cb.count(countSelectRoot));
|
||||
if (start != null && end != null) {
|
||||
countSelect.where(cb.between(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), start, end));
|
||||
countSelect.where(cb.between(countSelectRoot.get(JpaTarget_.lastTargetQuery), start, end));
|
||||
} else if (from == null && to != null) {
|
||||
countSelect.where(cb.lessThanOrEqualTo(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), end));
|
||||
countSelect.where(cb.lessThanOrEqualTo(countSelectRoot.get(JpaTarget_.lastTargetQuery), end));
|
||||
} else {
|
||||
countSelect.where(cb.isNull(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery)));
|
||||
countSelect.where(cb.isNull(countSelectRoot.get(JpaTarget_.lastTargetQuery)));
|
||||
}
|
||||
return countSelect;
|
||||
}
|
||||
@@ -314,10 +309,10 @@ public class JpaReportManagement implements ReportManagement {
|
||||
outerReportItems.add(outer.toItem());
|
||||
}
|
||||
} else {
|
||||
outerReportItems.add(new DataReportSeriesItem<String>("misc", inner.count));
|
||||
outerReportItems.add(new DataReportSeriesItem<>("misc", inner.count));
|
||||
}
|
||||
|
||||
innerOuterReport.add(new InnerOuterDataReportSeries<String>(
|
||||
innerOuterReport.add(new InnerOuterDataReportSeries<>(
|
||||
new DataReportSeries<>("DS-Name", Collections.singletonList(inner.toItem())),
|
||||
new DataReportSeries<>("DS-Version", outerReportItems)));
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
throw new RolloutIllegalStateException("First Group is not the first group.");
|
||||
}
|
||||
|
||||
deploymentManagement.startScheduledActionsByRolloutGroupParent(rollout, null);
|
||||
deploymentManagement.startScheduledActionsByRolloutGroupParent(rollout.getId(), null);
|
||||
|
||||
rolloutGroup.setStatus(RolloutGroupStatus.RUNNING);
|
||||
rolloutGroupRepository.save(rolloutGroup);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
@@ -242,4 +243,9 @@ public class JpaTagManagement implements TagManagement {
|
||||
return convertDsPage(distributionSetTagRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<TargetTag> findAllTargetTags(final Pageable pageable, final String controllerId) {
|
||||
return convertTPage(targetTagRepository.findAll(TagSpecification.ofTarget(controllerId), pageable), pageable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -20,8 +21,6 @@ import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.constraints.NotNull;
|
||||
@@ -38,11 +37,8 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
@@ -99,9 +95,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Autowired
|
||||
private TargetTagRepository targetTagRepository;
|
||||
|
||||
@Autowired
|
||||
private TargetInfoRepository targetInfoRepository;
|
||||
|
||||
@Autowired
|
||||
private NoCountPagingRepository criteriaNoCountDao;
|
||||
|
||||
@@ -122,28 +115,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return targetRepository.findByControllerId(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Target> findTargetByControllerIDWithDetails(final String controllerId) {
|
||||
final Optional<Target> result = targetRepository.findByControllerId(controllerId);
|
||||
// load lazy relations
|
||||
if (!result.isPresent()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.get().getTargetInfo().getControllerAttributes().size();
|
||||
if (result.get().getTargetInfo() != null
|
||||
&& result.get().getTargetInfo().getInstalledDistributionSet() != null) {
|
||||
result.get().getTargetInfo().getInstalledDistributionSet().getName();
|
||||
result.get().getTargetInfo().getInstalledDistributionSet().getModules().size();
|
||||
}
|
||||
if (result.get().getAssignedDistributionSet() != null) {
|
||||
result.get().getAssignedDistributionSet().getName();
|
||||
result.get().getAssignedDistributionSet().getModules().size();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> findTargetByControllerID(final Collection<String> controllerIDs) {
|
||||
return Collections.unmodifiableList(targetRepository
|
||||
@@ -157,16 +128,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findTargetsAll(final Pageable pageable) {
|
||||
// workarround - no join fetch allowed that is why we need specification
|
||||
// instead of query for
|
||||
// count() of Pageable
|
||||
final Specification<JpaTarget> spec = (root, query, cb) -> {
|
||||
if (!query.getResultType().isAssignableFrom(Long.class)) {
|
||||
root.fetch(JpaTarget_.targetInfo);
|
||||
}
|
||||
return cb.conjunction();
|
||||
};
|
||||
return convertPage(criteriaNoCountDao.findAll(spec, pageable, JpaTarget.class), pageable);
|
||||
return convertPage(criteriaNoCountDao.findAll(pageable, JpaTarget.class), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,14 +150,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return convertPage(targetRepository.findAll(spec, pageable), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Target> findTargetsByControllerIDsWithTags(final List<String> controllerIDs) {
|
||||
final List<List<String>> partition = Lists.partition(controllerIDs, Constants.MAX_ENTRIES_IN_STATEMENT);
|
||||
return partition.stream()
|
||||
.map(ids -> targetRepository.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(ids)))
|
||||
.flatMap(t -> t.stream()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@@ -205,11 +159,9 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final JpaTarget target = (JpaTarget) targetRepository.findByControllerId(update.getControllerId())
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, update.getControllerId()));
|
||||
|
||||
target.setNew(false);
|
||||
|
||||
update.getName().ifPresent(target::setName);
|
||||
update.getDescription().ifPresent(target::setDescription);
|
||||
update.getAddress().ifPresent(address -> ((JpaTargetInfo) target.getTargetInfo()).setAddress(address));
|
||||
update.getAddress().ifPresent(target::setAddress);
|
||||
update.getSecurityToken().ifPresent(target::setSecurityToken);
|
||||
|
||||
return targetRepository.save(target);
|
||||
@@ -282,7 +234,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public Page<Target> findTargetByInstalledDistributionSet(final Long distributionSetID, final Pageable pageReq) {
|
||||
throwEntityNotFoundIfDsDoesNotExist(distributionSetID);
|
||||
return targetRepository.findByTargetInfoInstalledDistributionSetId(pageReq, distributionSetID);
|
||||
return targetRepository.findByInstalledDistributionSetId(pageReq, distributionSetID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -303,7 +255,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Page<Target> findTargetByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) {
|
||||
return targetRepository.findByTargetInfoUpdateStatus(pageable, status);
|
||||
return targetRepository.findByUpdateStatus(pageable, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -312,8 +264,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final Boolean selectTargetWithNoTag, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(
|
||||
new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText,
|
||||
selectTargetWithNoTag, tagNames),
|
||||
true);
|
||||
selectTargetWithNoTag, tagNames));
|
||||
return findByCriteriaAPI(pageable, specList);
|
||||
}
|
||||
|
||||
@@ -323,16 +274,14 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final Boolean selectTargetWithNoTag, final String... tagNames) {
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(
|
||||
new FilterParams(installedOrAssignedDistributionSetId, status, overdueState, searchText,
|
||||
selectTargetWithNoTag, tagNames),
|
||||
true);
|
||||
selectTargetWithNoTag, tagNames));
|
||||
return countByCriteriaAPI(specList);
|
||||
}
|
||||
|
||||
private List<Specification<JpaTarget>> buildSpecificationList(final FilterParams filterParams,
|
||||
final boolean fetch) {
|
||||
private List<Specification<JpaTarget>> buildSpecificationList(final FilterParams filterParams) {
|
||||
final List<Specification<JpaTarget>> specList = new ArrayList<>();
|
||||
if (filterParams.getFilterByStatus() != null && !filterParams.getFilterByStatus().isEmpty()) {
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus(), fetch));
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus()));
|
||||
}
|
||||
if (filterParams.getOverdueState() != null) {
|
||||
specList.add(TargetSpecifications.isOverdue(TimestampCalculator.calculateOverdueTimestamp()));
|
||||
@@ -470,15 +419,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final CriteriaQuery<JpaTarget> query = cb.createQuery(JpaTarget.class);
|
||||
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
|
||||
|
||||
// necessary joins for the select
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfo = (Join<JpaTarget, JpaTargetInfo>) targetRoot
|
||||
.fetch(JpaTarget_.targetInfo, JoinType.LEFT);
|
||||
|
||||
// select case expression to retrieve the case value as a column to be
|
||||
// able to order based on
|
||||
// this column, installed first,...
|
||||
final Expression<Object> selectCase = cb.selectCase()
|
||||
.when(cb.equal(targetInfo.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id),
|
||||
.when(cb.equal(targetRoot.get(JpaTarget_.installedDistributionSet).get(JpaDistributionSet_.id),
|
||||
orderByDistributionId), 1)
|
||||
.when(cb.equal(targetRoot.get(JpaTarget_.assignedDistributionSet).get(JpaDistributionSet_.id),
|
||||
orderByDistributionId), 2)
|
||||
@@ -487,8 +432,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
query.distinct(true);
|
||||
// build the specifications and then to predicates necessary by the
|
||||
// given filters
|
||||
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(
|
||||
buildSpecificationList(filterParams, true), targetRoot, query, cb);
|
||||
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(buildSpecificationList(filterParams),
|
||||
targetRoot, query, cb);
|
||||
|
||||
// if we have some predicates then add it to the where clause of the
|
||||
// multiselect
|
||||
@@ -532,7 +477,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
public Long countTargetByInstalledDistributionSet(final Long distId) {
|
||||
throwEntityNotFoundIfDsDoesNotExist(distId);
|
||||
|
||||
return targetRepository.countByTargetInfoInstalledDistributionSetId(distId);
|
||||
return targetRepository.countByInstalledDistributionSetId(distId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -611,14 +556,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
throw new EntityAlreadyExistsException();
|
||||
}
|
||||
|
||||
target.setNew(true);
|
||||
final JpaTarget savedTarget = targetRepository.save(target);
|
||||
final JpaTargetInfo targetInfo = (JpaTargetInfo) savedTarget.getTargetInfo();
|
||||
|
||||
targetInfo.setNew(true);
|
||||
final Target targetToReturn = targetInfoRepository.save(targetInfo).getTarget();
|
||||
targetInfo.setNew(false);
|
||||
return targetToReturn;
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -668,4 +606,12 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
return Collections.unmodifiableList(targetRepository.findAll(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getControllerAttributes(final String controllerId) {
|
||||
final JpaTarget target = (JpaTarget) findTargetByControllerID(controllerId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
|
||||
return target.getControllerAttributes();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Usually a JPA spring data repository to handle {@link TargetInfo} entity.
|
||||
* However, do to an eclipselink bug with spring boot now a regular interface
|
||||
* that is implemented by {@link EclipseLinkTargetInfoRepository}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED)
|
||||
public interface TargetInfoRepository {
|
||||
|
||||
/**
|
||||
* Sets new TargetUpdateStatus of given target if is not already on that
|
||||
* value.
|
||||
*
|
||||
* @param status
|
||||
* to set
|
||||
* @param targets
|
||||
* to set it for
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Query("update JpaTargetInfo ti set ti.updateStatus = :status where ti.targetId in :targets and ti.updateStatus != :status")
|
||||
void setTargetUpdateStatus(@Param("status") TargetUpdateStatus status, @Param("targets") List<Long> targets);
|
||||
|
||||
/**
|
||||
* Save entity and evict cache with it.
|
||||
*
|
||||
* @param entity
|
||||
* to persists
|
||||
*
|
||||
* @return persisted or updated {@link Entity}
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
<S extends JpaTargetInfo> S save(S entity);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -17,12 +18,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@@ -38,19 +36,43 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>, JpaSpecificationExecutor<JpaTarget> {
|
||||
|
||||
/**
|
||||
* Loads {@link Target} including details {@link EntityGraph} by given ID.
|
||||
* Sets {@link JpaTarget#getAssignedDistributionSet()}.
|
||||
*
|
||||
* @param set
|
||||
* to use
|
||||
* @param status
|
||||
* to set
|
||||
* @param modifiedAt
|
||||
* current time
|
||||
* @param modifiedBy
|
||||
* current auditor
|
||||
* @param targets
|
||||
* to update
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy, t.updateStatus = :status WHERE t.id IN :targets")
|
||||
void setAssignedDistributionSetAndUpdateStatus(@Param("status") TargetUpdateStatus status,
|
||||
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
/**
|
||||
* Loads {@link Target} by given ID.
|
||||
*
|
||||
* @param controllerID
|
||||
* to search for
|
||||
* @return found {@link Target} or <code>null</code> if not found.
|
||||
*/
|
||||
@EntityGraph(value = "Target.detail", type = EntityGraphType.LOAD)
|
||||
Optional<Target> findByControllerId(String controllerID);
|
||||
|
||||
@Query("SELECT t.controllerAttributes FROM JpaTarget t WHERE t.controllerId=:controllerId")
|
||||
Map<String, String> getControllerAttributes(@Param("controllerId") String controllerId);
|
||||
|
||||
/**
|
||||
* Checks if target with given id exists.
|
||||
*
|
||||
* @param controllerId to check
|
||||
* @param controllerId
|
||||
* to check
|
||||
* @return <code>true</code> if target with given id exists
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(t)>0 THEN 'true' ELSE 'false' END FROM JpaTarget t WHERE t.controllerId=:controllerId")
|
||||
@@ -102,7 +124,7 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
||||
*
|
||||
* @return found targets
|
||||
*/
|
||||
Page<Target> findByTargetInfoUpdateStatus(final Pageable pageable, final TargetUpdateStatus status);
|
||||
Page<Target> findByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status);
|
||||
|
||||
/**
|
||||
* retrieves the {@link Target}s which has the {@link DistributionSet}
|
||||
@@ -114,7 +136,7 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
||||
* the ID of the {@link DistributionSet}
|
||||
* @return the found {@link Target}s
|
||||
*/
|
||||
Page<Target> findByTargetInfoInstalledDistributionSetId(final Pageable pageable, final Long setID);
|
||||
Page<Target> findByInstalledDistributionSetId(final Pageable pageable, final Long setID);
|
||||
|
||||
/**
|
||||
* Finds all targets that have defined {@link DistributionSet} assigned.
|
||||
@@ -141,13 +163,13 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
||||
|
||||
/**
|
||||
* Counts number of targets with given
|
||||
* {@link TargetInfo#getInstalledDistributionSet()}.
|
||||
* {@link Target#getInstalledDistributionSet()}.
|
||||
*
|
||||
* @param distId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s.
|
||||
*/
|
||||
Long countByTargetInfoInstalledDistributionSetId(final Long distId);
|
||||
Long countByInstalledDistributionSetId(final Long distId);
|
||||
|
||||
/**
|
||||
* Finds all {@link Target}s in the repository.
|
||||
@@ -164,24 +186,6 @@ public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>,
|
||||
@Query("SELECT t FROM JpaTarget t WHERE t.id IN ?1")
|
||||
List<JpaTarget> findAll(Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Sets {@link Target#getAssignedDistributionSet()}.
|
||||
*
|
||||
* @param set
|
||||
* to use
|
||||
* @param modifiedAt
|
||||
* current time
|
||||
* @param modifiedBy
|
||||
* current auditor
|
||||
* @param targets
|
||||
* to update
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy WHERE t.id IN :targets")
|
||||
void setAssignedDistributionSet(@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
/**
|
||||
*
|
||||
* Finds all targets of a rollout group.
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.hawkbit.repository.builder.AbstractTargetUpdateCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
|
||||
/**
|
||||
@@ -40,11 +39,9 @@ public class JpaTargetCreate extends AbstractTargetUpdateCreate<TargetCreate> im
|
||||
}
|
||||
|
||||
target.setDescription(description);
|
||||
final JpaTargetInfo targetInfo = (JpaTargetInfo) target.getTargetInfo();
|
||||
|
||||
targetInfo.setAddress(address);
|
||||
targetInfo.setUpdateStatus(getStatus().orElse(TargetUpdateStatus.UNKNOWN));
|
||||
getLastTargetQuery().ifPresent(targetInfo::setLastTargetQuery);
|
||||
target.setAddress(address);
|
||||
target.setUpdateStatus(getStatus().orElse(TargetUpdateStatus.UNKNOWN));
|
||||
getLastTargetQuery().ifPresent(target::setLastTargetQuery);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,14 @@ import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* Holder of the base attributes common to all entities.
|
||||
@@ -72,26 +74,26 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_at", insertable = false, updatable = true)
|
||||
@Column(name = "last_modified_at", insertable = true, updatable = true)
|
||||
public Long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_by", insertable = false, updatable = true, length = 40)
|
||||
@Column(name = "last_modified_by", insertable = true, updatable = true, length = 40)
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
@CreatedBy
|
||||
public void setCreatedBy(final String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
if (isController()) {
|
||||
this.createdBy = "CONTROLLER_PLUG_AND_PLAY";
|
||||
return;
|
||||
}
|
||||
|
||||
@LastModifiedBy
|
||||
public void setLastModifiedBy(final String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
@CreatedDate
|
||||
@@ -101,9 +103,30 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||
|
||||
@LastModifiedDate
|
||||
public void setLastModifiedAt(final Long lastModifiedAt) {
|
||||
|
||||
if (isController()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastModifiedAt = lastModifiedAt;
|
||||
}
|
||||
|
||||
@LastModifiedBy
|
||||
public void setLastModifiedBy(final String lastModifiedBy) {
|
||||
if (isController()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
private boolean isController() {
|
||||
return SecurityContextHolder.getContext().getAuthentication()
|
||||
.getDetails() instanceof TenantAwareAuthenticationDetails
|
||||
&& ((TenantAwareAuthenticationDetails) SecurityContextHolder.getContext().getAuthentication()
|
||||
.getDetails()).isController();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOptLockRevision() {
|
||||
return optLockRevision;
|
||||
|
||||
@@ -11,6 +11,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;
|
||||
import org.eclipse.persistence.queries.UpdateObjectQuery;
|
||||
|
||||
/**
|
||||
* Listens to change in property values of an entity and calls the corresponding
|
||||
@@ -29,10 +30,13 @@ public class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
||||
|
||||
@Override
|
||||
public void postUpdate(final DescriptorEvent event) {
|
||||
|
||||
final Object object = event.getObject();
|
||||
if (isEventAwareEntity(object)) {
|
||||
if (isEventAwareEntity(object)
|
||||
&& isFireUpdate((EventAwareEntity) object, (UpdateObjectQuery) event.getQuery())) {
|
||||
doNotifiy(() -> ((EventAwareEntity) object).fireUpdateEvent(event));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,4 +55,9 @@ public class EntityPropertyChangeListener extends DescriptorEventAdapter {
|
||||
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(runnable);
|
||||
}
|
||||
|
||||
private static boolean isFireUpdate(final EventAwareEntity entity, final UpdateObjectQuery query) {
|
||||
return entity.getUpdateIgnoreFields().isEmpty() || query.getObjectChangeSet().getChangedAttributeNames()
|
||||
.stream().anyMatch(field -> !entity.getUpdateIgnoreFields().contains(field));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
|
||||
/**
|
||||
@@ -36,4 +39,12 @@ public interface EventAwareEntity {
|
||||
* @param descriptorEvent
|
||||
*/
|
||||
void fireDeleteEvent(DescriptorEvent descriptorEvent);
|
||||
|
||||
/**
|
||||
* @return list of entity fields that if the only changed fields prevents
|
||||
* {@link #fireUpdateEvent(DescriptorEvent)} call.
|
||||
*/
|
||||
default List<String> getUpdateIgnoreFields() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
@OneToMany(mappedBy = "autoAssignDistributionSet", targetEntity = JpaTargetFilterQuery.class, fetch = FetchType.LAZY)
|
||||
private List<TargetFilterQuery> autoAssignFilters;
|
||||
|
||||
@OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY)
|
||||
private List<JpaTargetInfo> installedAtTargets;
|
||||
@OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY)
|
||||
private List<JpaTarget> installedAtTargets;
|
||||
|
||||
@OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY)
|
||||
private List<JpaAction> actions;
|
||||
|
||||
@@ -8,16 +8,27 @@
|
||||
*/
|
||||
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.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.Index;
|
||||
@@ -25,14 +36,11 @@ 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.MapKeyColumn;
|
||||
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.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
@@ -45,14 +53,21 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHol
|
||||
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.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.springframework.data.domain.Persistable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link Target}.
|
||||
@@ -64,26 +79,27 @@ import org.springframework.data.domain.Persistable;
|
||||
@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_05", columnList = "tenant,address"),
|
||||
@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<Long>, Target, EventAwareEntity {
|
||||
public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAwareEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaTarget.class);
|
||||
|
||||
private static final List<String> TARGET_UPDATE_EVENT_IGNORE_FIELDS = Lists.newArrayList("lastTargetQuery",
|
||||
"lastTargetQuery", "address", "optLockRevision", "lastModifiedAt", "lastModifiedBy");
|
||||
|
||||
@Column(name = "controller_id", length = 64)
|
||||
@Size(min = 1, max = 64)
|
||||
@NotEmpty
|
||||
@Pattern(regexp = "[.\\S]*", message = "has whitespaces which are not allowed")
|
||||
private String controllerId;
|
||||
|
||||
@Transient
|
||||
private boolean entityNew;
|
||||
|
||||
@CascadeOnDelete
|
||||
@ManyToMany(targetEntity = JpaTargetTag.class)
|
||||
@JoinTable(name = "sp_target_target_tag", joinColumns = {
|
||||
@@ -95,16 +111,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
@OneToMany(mappedBy = "target", fetch = FetchType.LAZY, targetEntity = JpaAction.class)
|
||||
private List<JpaAction> actions;
|
||||
|
||||
@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.PERSIST,
|
||||
CascadeType.MERGE }, 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.
|
||||
@@ -118,6 +124,46 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
@OneToMany(mappedBy = "target", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST })
|
||||
private List<RolloutTargetGroup> rolloutTargetGroup;
|
||||
|
||||
@Column(name = "address", length = 512)
|
||||
@Size(max = 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 = 16)
|
||||
@Enumerated(EnumType.STRING)
|
||||
@NotNull
|
||||
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;
|
||||
|
||||
@ManyToOne(optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds"))
|
||||
private JpaDistributionSet assignedDistributionSet;
|
||||
|
||||
/**
|
||||
* Read only on management API. Are committed by controller.
|
||||
*/
|
||||
@CascadeOnDelete
|
||||
@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", nullable = false, updatable = false) }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
|
||||
|
||||
// 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.
|
||||
*
|
||||
@@ -140,14 +186,12 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
this.controllerId = controllerId;
|
||||
setName(controllerId);
|
||||
this.securityToken = securityToken;
|
||||
targetInfo = new JpaTargetInfo(this);
|
||||
}
|
||||
|
||||
JpaTarget() {
|
||||
// empty constructor for JPA.
|
||||
}
|
||||
|
||||
@Override
|
||||
public DistributionSet getAssignedDistributionSet() {
|
||||
return assignedDistributionSet;
|
||||
}
|
||||
@@ -157,7 +201,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
return controllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TargetTag> getTags() {
|
||||
if (tags == null) {
|
||||
return Collections.emptySet();
|
||||
@@ -198,7 +241,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
this.controllerId = controllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getActions() {
|
||||
if (actions == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -215,36 +257,6 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
return actions.add((JpaAction) action);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transient
|
||||
public boolean isNew() {
|
||||
return entityNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityNew
|
||||
* 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}
|
||||
@@ -260,17 +272,110 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param securityToken
|
||||
* the securityToken to set
|
||||
*/
|
||||
public void setSecurityToken(final String securityToken) {
|
||||
this.securityToken = securityToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Long getLastTargetQuery() {
|
||||
return lastTargetQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getInstallationDate() {
|
||||
return installationDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetUpdateStatus getUpdateStatus() {
|
||||
return updateStatus;
|
||||
}
|
||||
|
||||
public JpaDistributionSet getInstalledDistributionSet() {
|
||||
return installedDistributionSet;
|
||||
}
|
||||
|
||||
public Map<String, String> getControllerAttributes() {
|
||||
return controllerAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRequestControllerAttributes() {
|
||||
return requestControllerAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]";
|
||||
return "JpaTarget [controllerId=" + controllerId + ", revision=" + getOptLockRevision() + ", id=" + getId()
|
||||
+ "]";
|
||||
}
|
||||
|
||||
public void setAddress(final String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void setLastTargetQuery(final Long lastTargetQuery) {
|
||||
this.lastTargetQuery = lastTargetQuery;
|
||||
}
|
||||
|
||||
public void setInstallationDate(final Long installationDate) {
|
||||
this.installationDate = installationDate;
|
||||
}
|
||||
|
||||
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
|
||||
this.installedDistributionSet = installedDistributionSet;
|
||||
}
|
||||
|
||||
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
|
||||
this.updateStatus = updateStatus;
|
||||
}
|
||||
|
||||
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
|
||||
this.requestControllerAttributes = requestControllerAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,6 +384,11 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
|
||||
.publishEvent(new TargetCreatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUpdateIgnoreFields() {
|
||||
return TARGET_UPDATE_EVENT_IGNORE_FIELDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher()
|
||||
|
||||
@@ -1,310 +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.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 javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.PollStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.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
|
||||
@EntityListeners(EntityPropertyChangeListener.class)
|
||||
public class JpaTargetInfo implements Persistable<Long>, 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 }, 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)
|
||||
@Size(max = 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 = 16)
|
||||
@Enumerated(EnumType.STRING)
|
||||
@NotNull
|
||||
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.
|
||||
*/
|
||||
@CascadeOnDelete
|
||||
@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", nullable = false, updatable = false) }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
|
||||
|
||||
// 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 JpaTargetInfo}.
|
||||
*
|
||||
* @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 entityNew
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAddress(final String address) {
|
||||
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<String, String> 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;
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,8 @@ public class StartNextGroupRolloutGroupSuccessAction implements RolloutGroupActi
|
||||
// retrieve all actions according to the parent group of the finished
|
||||
// rolloutGroup, so retrieve all child-group actions which need to be
|
||||
// started.
|
||||
final long countOfStartedActions = deploymentManagement.startScheduledActionsByRolloutGroupParent(rollout,
|
||||
rolloutGroup);
|
||||
final long countOfStartedActions = deploymentManagement
|
||||
.startScheduledActionsByRolloutGroupParent(rollout.getId(), rolloutGroup.getId());
|
||||
logger.debug("{} Next actions started for rollout {} and parent group {}", countOfStartedActions, rollout,
|
||||
rolloutGroup);
|
||||
if (countOfStartedActions > 0) {
|
||||
|
||||
@@ -11,7 +11,6 @@ package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Path;
|
||||
@@ -24,8 +23,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -200,10 +197,9 @@ public final class DistributionSetSpecification {
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> installedTarget(final String installedTargetId) {
|
||||
return (dsRoot, query, cb) -> {
|
||||
final ListJoin<JpaDistributionSet, JpaTargetInfo> installedTargetJoin = dsRoot
|
||||
final ListJoin<JpaDistributionSet, JpaTarget> installedTargetJoin = dsRoot
|
||||
.join(JpaDistributionSet_.installedAtTargets, JoinType.INNER);
|
||||
final Join<JpaTargetInfo, JpaTarget> targetJoin = installedTargetJoin.join(JpaTargetInfo_.target);
|
||||
return cb.equal(targetJoin.get(JpaTarget_.controllerId), installedTargetId);
|
||||
return cb.equal(installedTargetJoin.get(JpaTarget_.controllerId), installedTargetId);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.specifications;
|
||||
|
||||
import javax.persistence.criteria.Join;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Specifications class for {@link Tag}s. The class provides Spring Data JPQL
|
||||
* Specifications.
|
||||
*
|
||||
*/
|
||||
public final class TagSpecification {
|
||||
private TagSpecification() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* DELETED attribute.
|
||||
*
|
||||
* @param isDeleted
|
||||
* TRUE/FALSE are compared to the attribute DELETED. If NULL the
|
||||
* attribute is ignored
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTargetTag> ofTarget(final String controllerId) {
|
||||
return (targetRoot, query, criteriaBuilder) -> {
|
||||
final Join<JpaTargetTag, JpaTarget> tagJoin = targetRoot.join(JpaTargetTag_.assignedToTargets);
|
||||
|
||||
query.distinct(true);
|
||||
|
||||
return criteriaBuilder.equal(tagJoin.get(JpaTarget_.controllerId), controllerId);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Path;
|
||||
@@ -27,8 +26,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
@@ -37,7 +34,6 @@ import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetInfo;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
@@ -101,20 +97,8 @@ public final class TargetSpecifications {
|
||||
* join it.
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTargetUpdateStatus(final Collection<TargetUpdateStatus> updateStatus,
|
||||
final boolean fetch) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
if (!query.getResultType().isAssignableFrom(Long.class)) {
|
||||
if (fetch) {
|
||||
targetRoot.fetch(JpaTarget_.targetInfo);
|
||||
} else {
|
||||
targetRoot.join(JpaTarget_.targetInfo);
|
||||
}
|
||||
return targetRoot.get(JpaTarget_.targetInfo).get(JpaTargetInfo_.updateStatus).in(updateStatus);
|
||||
}
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo);
|
||||
return targetInfoJoin.get(JpaTargetInfo_.updateStatus).in(updateStatus);
|
||||
};
|
||||
public static Specification<JpaTarget> hasTargetUpdateStatus(final Collection<TargetUpdateStatus> updateStatus) {
|
||||
return (targetRoot, query, cb) -> targetRoot.get(JpaTarget_.updateStatus).in(updateStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,10 +118,8 @@ public final class TargetSpecifications {
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> isOverdue(final long overdueTimestamp) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo);
|
||||
return cb.lessThanOrEqualTo(targetInfoJoin.get(JpaTargetInfo_.lastTargetQuery), overdueTimestamp);
|
||||
};
|
||||
return (targetRoot, query, cb) -> cb.lessThanOrEqualTo(targetRoot.get(JpaTarget_.lastTargetQuery),
|
||||
overdueTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,14 +148,11 @@ public final class TargetSpecifications {
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasInstalledOrAssignedDistributionSet(@NotNull final Long distributionId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo);
|
||||
return cb.or(
|
||||
cb.equal(targetInfoJoin.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id),
|
||||
distributionId),
|
||||
cb.equal(targetRoot.<JpaDistributionSet> get(JpaTarget_.assignedDistributionSet)
|
||||
.get(JpaDistributionSet_.id), distributionId));
|
||||
};
|
||||
return (targetRoot, query, cb) -> cb.or(
|
||||
cb.equal(targetRoot.get(JpaTarget_.installedDistributionSet).get(JpaDistributionSet_.id),
|
||||
distributionId),
|
||||
cb.equal(targetRoot.<JpaDistributionSet> get(JpaTarget_.assignedDistributionSet)
|
||||
.get(JpaDistributionSet_.id), distributionId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,10 +288,7 @@ public final class TargetSpecifications {
|
||||
* @return the {@link Target} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaTarget> hasInstalledDistributionSet(final Long distributionSetId) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Join<JpaTarget, JpaTargetInfo> targetInfoJoin = targetRoot.join(JpaTarget_.targetInfo);
|
||||
return cb.equal(targetInfoJoin.get(JpaTargetInfo_.installedDistributionSet).get(JpaDistributionSet_.id),
|
||||
distributionSetId);
|
||||
};
|
||||
return (targetRoot, query, cb) -> cb.equal(
|
||||
targetRoot.get(JpaTarget_.installedDistributionSet).get(JpaDistributionSet_.id), distributionSetId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
ALTER TABLE sp_target ADD COLUMN install_date bigint;
|
||||
ALTER TABLE sp_target ADD COLUMN address varchar(512);
|
||||
ALTER TABLE sp_target ADD COLUMN last_target_query bigint;
|
||||
ALTER TABLE sp_target ADD COLUMN request_controller_attributes bit not null;
|
||||
ALTER TABLE sp_target ADD COLUMN update_status varchar(16) not null;
|
||||
ALTER TABLE sp_target ADD COLUMN installed_distribution_set bigint;
|
||||
|
||||
UPDATE sp_target t SET install_date=(SELECT i.install_date FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
UPDATE sp_target t SET address=(SELECT i.address FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
UPDATE sp_target t SET last_target_query=(SELECT i.last_target_query FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
UPDATE sp_target t SET request_controller_attributes=(SELECT i.request_controller_attributes FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
UPDATE sp_target t SET update_status=(SELECT i.update_status FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
UPDATE sp_target t SET installed_distribution_set=(SELECT i.installed_distribution_set FROM sp_target_info i WHERE t.id = i.target_id);
|
||||
|
||||
ALTER TABLE sp_target_attributes DROP CONSTRAINT fk_targ_attrib_target;
|
||||
ALTER TABLE sp_target_attributes
|
||||
ADD CONSTRAINT fk_targ_attrib_target
|
||||
FOREIGN KEY (target_id)
|
||||
REFERENCES sp_target (id)
|
||||
ON DELETE cascade;
|
||||
|
||||
ALTER TABLE sp_target_info DROP CONSTRAINT fk_target_inst_ds;
|
||||
ALTER TABLE sp_target
|
||||
ADD CONSTRAINT fk_target_inst_ds
|
||||
FOREIGN KEY (installed_distribution_set)
|
||||
REFERENCES sp_distribution_set (id);
|
||||
|
||||
ALTER TABLE sp_target_info DROP CONSTRAINT fk_targ_stat_targ;
|
||||
ALTER TABLE sp_target_info DROP INDEX sp_idx_target_info_02;
|
||||
CREATE INDEX sp_idx_target_05 ON sp_target (tenant,address);
|
||||
|
||||
DROP TABLE sp_target_info;
|
||||
@@ -0,0 +1,32 @@
|
||||
ALTER TABLE sp_target ADD COLUMN install_date bigint;
|
||||
ALTER TABLE sp_target ADD COLUMN address varchar(512);
|
||||
ALTER TABLE sp_target ADD COLUMN last_target_query bigint;
|
||||
ALTER TABLE sp_target ADD COLUMN request_controller_attributes bit not null;
|
||||
ALTER TABLE sp_target ADD COLUMN update_status varchar(16) not null;
|
||||
ALTER TABLE sp_target ADD COLUMN installed_distribution_set bigint;
|
||||
|
||||
UPDATE sp_target AS t INNER JOIN sp_target_info AS i
|
||||
ON t.id = i.target_id
|
||||
SET t.install_date = i.install_date, t.address = i.address,t.last_target_query = i.last_target_query,
|
||||
t.request_controller_attributes = i.request_controller_attributes,t.update_status = i.update_status,
|
||||
t.installed_distribution_set = i.installed_distribution_set;
|
||||
|
||||
ALTER TABLE sp_target_info DROP INDEX sp_idx_target_info_02;
|
||||
CREATE INDEX sp_idx_target_05 ON sp_target (tenant,address);
|
||||
|
||||
ALTER TABLE sp_target_attributes DROP FOREIGN KEY fk_targ_attrib_target;
|
||||
ALTER TABLE sp_target_attributes
|
||||
ADD CONSTRAINT fk_targ_attrib_target
|
||||
FOREIGN KEY (target_id)
|
||||
REFERENCES sp_target (id)
|
||||
ON DELETE cascade;
|
||||
|
||||
ALTER TABLE sp_target_info DROP FOREIGN KEY fk_target_inst_ds;
|
||||
ALTER TABLE sp_target
|
||||
ADD CONSTRAINT fk_target_inst_ds
|
||||
FOREIGN KEY (installed_distribution_set)
|
||||
REFERENCES sp_distribution_set (id);
|
||||
|
||||
ALTER TABLE sp_target_info DROP FOREIGN KEY fk_targ_stat_targ;
|
||||
|
||||
DROP TABLE sp_target_info;
|
||||
Reference in New Issue
Block a user