diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java index d6b57f14c7..0aecfa29fb 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/management/JpaControllerManagement.java @@ -197,34 +197,6 @@ public int getWeightConsideringDefault(final Action action) { return super.getWeightConsideringDefault(action); } - @Override - protected void onActionStatusUpdate(final JpaActionStatus newActionStatus, final JpaAction action) { - final Action.Status updatedActionStatus = newActionStatus.getStatus(); - final long timestamp = newActionStatus.getTimestamp(); - switch (updatedActionStatus) { - case ERROR: { - final JpaTarget target = action.getTarget(); - target.setUpdateStatus(TargetUpdateStatus.ERROR); - handleErrorOnAction(action, target); - break; - } - case FINISHED: { - requestControllerAttributes(handleFinishedAndStoreInTargetStatus(timestamp, action)); - break; - } - case DOWNLOADED: { - handleDownloadedActionStatus(action).ifPresent(controllerId -> - requestControllerAttributes(findByControllerId(controllerId) - .map(JpaTarget.class::cast) - .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)))); - break; - } - default: { - break; - } - } - } - @Override @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(includes = ConcurrencyFailureException.class, maxRetriesString = Constants.RETRY_MAX, delayString = Constants.RETRY_DELAY) @@ -271,7 +243,7 @@ public Map> findTargetVisibleMetaDataBySoftwareModuleI } @Override - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(includes = ConcurrencyFailureException.class, maxRetriesString = Constants.RETRY_MAX, delayString = Constants.RETRY_DELAY) public ActionStatus addInformationalActionStatus(final ActionStatusCreate create) { final JpaAction action = actionRepository.getById(create.getActionId()); @@ -348,13 +320,6 @@ public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, fi return findOrRegisterTargetIfItDoesNotExist0(controllerId, address, name, type); } - private Target findOrRegisterTargetIfItDoesNotExist0(final String controllerId, final URI address, final String name, final String type) { - final Specification spec = (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.controllerId), controllerId); - return targetRepository.findOne(spec) - .map(target -> updateTarget(target, address, name, type)) - .orElseGet(() -> createTarget(controllerId, address, name, type)); - } - @Override public Action getActionForDownloadByTargetAndSoftwareModule(final String controllerId, final long moduleId) { throwExceptionIfTargetDoesNotExist(controllerId); @@ -426,14 +391,14 @@ public boolean hasTargetArtifactAssigned(final long targetId, final String sha1H } @Override - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(includes = ConcurrencyFailureException.class, maxRetriesString = Constants.RETRY_MAX, delayString = Constants.RETRY_DELAY) public void registerRetrieved(final long actionId, final String message) { handleRegisterRetrieved(actionId, message); } @Override - @Transactional + @Transactional(isolation = Isolation.READ_COMMITTED) @Retryable(includes = ConcurrencyFailureException.class, maxRetriesString = Constants.RETRY_MAX, delayString = Constants.RETRY_DELAY) public Target updateControllerAttributes(final String controllerId, final Map data, final UpdateMode mode) { // Constraints on attribute keys & values are not validated by EclipseLink. Hence, they are validated here. @@ -544,6 +509,7 @@ public Action cancelAction(final Action action) { } @Override + @Transactional(isolation = Isolation.READ_COMMITTED) public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) { // if access control for target repository is present check that caller has UPDATE access to the target of the action targetRepository.getAccessController().ifPresent( @@ -554,6 +520,7 @@ public void updateActionExternalRef(final long actionId, @NotEmpty final String } @Override + @Transactional(isolation = Isolation.READ_COMMITTED) public void deleteExistingTarget(@NotEmpty final String controllerId) { final JpaTarget target = targetRepository.getByControllerId(controllerId); targetRepository.deleteById(target.getId()); @@ -569,16 +536,19 @@ public Optional findInstalledActionByTarget(final Target target) { } @Override + @Transactional(isolation = Isolation.READ_COMMITTED) public AutoConfirmationStatus activateAutoConfirmation(final String controllerId, final String initiator, final String remark) { return confirmationManagement.activateAutoConfirmation(controllerId, initiator, remark); } @Override + @Transactional(isolation = Isolation.READ_COMMITTED) public void deactivateAutoConfirmation(final String controllerId) { confirmationManagement.deactivateAutoConfirmation(controllerId); } @Override + @Transactional(isolation = Isolation.READ_COMMITTED) public boolean updateOfflineAssignedVersion(@NotEmpty final String controllerId, final String distributionName, final String version) { List distributionSetAssignmentResults = asSystem(() -> asActor(controllerId, () -> deploymentManagement.offlineAssignedDistributionSets( @@ -590,8 +560,33 @@ public boolean updateOfflineAssignedVersion(@NotEmpty final String controllerId, .orElseThrow(); } - private Optional findTargetType(String targetTypeName) { - return targetTypeRepository.findOne(TargetTypeSpecification.hasName(targetTypeName)).map(TargetType.class::cast); + // transaction write contract shall be handled by the callers + @Override + protected void onActionStatusUpdate(final JpaActionStatus newActionStatus, final JpaAction action) { + final Action.Status updatedActionStatus = newActionStatus.getStatus(); + final long timestamp = newActionStatus.getTimestamp(); + switch (updatedActionStatus) { + case ERROR: { + final JpaTarget target = action.getTarget(); + target.setUpdateStatus(TargetUpdateStatus.ERROR); + handleErrorOnAction(action, target); + break; + } + case FINISHED: { + requestControllerAttributes(handleFinishedAndStoreInTargetStatus(timestamp, action)); + break; + } + case DOWNLOADED: { + handleDownloadedActionStatus(action).ifPresent(controllerId -> + requestControllerAttributes(findByControllerId(controllerId) + .map(JpaTarget.class::cast) + .orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId)))); + break; + } + default: { + break; + } + } } // for testing @@ -599,6 +594,17 @@ void setTargetRepository(final TargetRepository targetRepositorySpy) { this.targetRepository = targetRepositorySpy; } + private Target findOrRegisterTargetIfItDoesNotExist0(final String controllerId, final URI address, final String name, final String type) { + final Specification spec = (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaTarget_.controllerId), controllerId); + return targetRepository.findOne(spec) + .map(target -> updateTarget(target, address, name, type)) + .orElseGet(() -> createTarget(controllerId, address, name, type)); + } + + private Optional findTargetType(String targetTypeName) { + return targetTypeRepository.findOne(TargetTypeSpecification.hasName(targetTypeName)).map(TargetType.class::cast); + } + private static boolean isAddressChanged(final URI addressToUpdate, final URI address) { return addressToUpdate == null || !addressToUpdate.equals(address); }