Feature add optional name to thing created (#888)

* First implementation pushed because of debugging purpose

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Add name field and tests regarding name field functionality in THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* SonarQube realted changes in name field functionality in THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Add name field and tests regarding name field functionality in UPDATE_ATTRIBUTES

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Adapt documentation due to name field in THING_CREATED and UPDATE_ATTRIBUTES

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Add integration tests regarding name field functionality in THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Reformat after finding format bug regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Reformat after finding the real format bug regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Reformat regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Use constant in THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Format in THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Resolving peer review comments regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Resolving peer review comments (organize imports) regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Refactoring regarding THING_CREATED

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Refactoring due to peer review

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Refactoring due to peer review

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Excluding UPDATE_ATTRIBUTES changes and provide functionality of updating the name property in THING_CREATED message

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Refactoring due to peer review

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Refactoring due to peer review

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Fix SonarQube finding

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Merge master into current branch

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>

* Fix peer review findings

Signed-off-by: Ammar Bikic <ammar.bikic@bosch-si.com>
This commit is contained in:
Ammar Bikic
2019-10-24 12:13:35 +02:00
committed by Dominic Schabel
parent b50a82fc0f
commit af0f7ceb5a
10 changed files with 525 additions and 388 deletions

View File

@@ -97,6 +97,7 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import com.google.common.collect.Lists;
@@ -238,11 +239,11 @@ public class JpaControllerManagement implements ControllerManagement {
* Constructor.
*
* @param defaultEventInterval
* default timer value to use for interval between events.
* This puts an upper bound for the timer value
* default timer value to use for interval between events. This puts
* an upper bound for the timer value
* @param minimumEventInterval
* for loading {@link DistributionSet#getModules()}. This
* puts a lower bound to the timer value
* for loading {@link DistributionSet#getModules()}. This puts a
* lower bound to the timer value
* @param timeUnit
* representing the unit of time to be used for timer.
*/
@@ -257,16 +258,15 @@ public class JpaControllerManagement implements ControllerManagement {
}
/**
* This method calculates the time interval until the next event based
* on the desired number of events before the time when interval is
* reset to default. The return value is bounded by
* {@link EventTimer#defaultEventInterval} and
* This method calculates the time interval until the next event based on the
* desired number of events before the time when interval is reset to default.
* The return value is bounded by {@link EventTimer#defaultEventInterval} and
* {@link EventTimer#minimumEventInterval}.
*
* @param eventCount
* number of events desired until the interval is reset to
* default. This is not guaranteed as the interval between
* events cannot be less than the minimum interval
* number of events desired until the interval is reset to default.
* This is not guaranteed as the interval between events cannot be
* less than the minimum interval
* @param timerResetTime
* time when exponential forwarding should reset to default
*
@@ -386,16 +386,25 @@ public class JpaControllerManagement implements ControllerManagement {
@Transactional(isolation = Isolation.READ_COMMITTED)
@Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address) {
return findOrRegisterTargetIfItDoesNotExist(controllerId, address, null);
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED)
@Retryable(include = ConcurrencyFailureException.class, exclude = EntityAlreadyExistsException.class, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public Target findOrRegisterTargetIfItDoesNotExist(final String controllerId, final URI address,
final String name) {
final Specification<JpaTarget> spec = (targetRoot, query, cb) -> cb
.equal(targetRoot.get(JpaTarget_.controllerId), controllerId);
return targetRepository.findOne(spec).map(target -> updateTargetStatus(target, address))
.orElseGet(() -> createTarget(controllerId, address));
return targetRepository.findOne(spec).map(target -> updateTarget(target, address, name))
.orElseGet(() -> createTarget(controllerId, address, name));
}
private Target createTarget(final String controllerId, final URI address) {
private Target createTarget(final String controllerId, final URI address, String name) {
final Target result = targetRepository.save((JpaTarget) entityFactory.target().create()
.controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId)
.controllerId(controllerId).description("Plug and Play target: " + controllerId).name((StringUtils.hasText(name) ? name : controllerId))
.status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis())
.address(Optional.ofNullable(address).map(URI::toString).orElse(null)).build());
@@ -458,9 +467,8 @@ public class JpaControllerManagement implements ControllerManagement {
/**
* Sets {@link Target#getLastTargetQuery()} by native SQL in order to avoid
* raising opt lock revision as this update is not mission critical and in
* fact only written by {@link ControllerManagement}, i.e. the target
* itself.
* raising opt lock revision as this update is not mission critical and in fact
* only written by {@link ControllerManagement}, i.e. the target itself.
*/
private void setLastTargetQuery(final String tenant, final long currentTimeMillis, final List<String> chunk) {
final Map<String, String> paramMapping = Maps.newHashMapWithExpectedSize(chunk.size());
@@ -488,39 +496,40 @@ public class JpaControllerManagement implements ControllerManagement {
}
/**
* Stores target directly to DB in case either {@link Target#getAddress()}
* or {@link Target#getUpdateStatus()} changes or the buffer queue is full.
* Stores target directly to DB in case either {@link Target#getAddress()} or
* {@link Target#getUpdateStatus()} or {@link Target#getName()} changes or the buffer queue is full.
*
*/
private Target updateTargetStatus(final JpaTarget toUpdate, final URI address) {
boolean storeEager = isStoreEager(toUpdate, address);
if (TargetUpdateStatus.UNKNOWN == toUpdate.getUpdateStatus()) {
toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED);
storeEager = true;
}
if (storeEager || !queue.offer(new TargetPoll(toUpdate))) {
toUpdate.setAddress(address.toString());
private Target updateTarget(final JpaTarget toUpdate, final URI address, final String name) {
if (isStoreEager(toUpdate, address, name) || !queue.offer(new TargetPoll(toUpdate))) {
if (isAddressChanged(toUpdate.getAddress(), address)) {
toUpdate.setAddress(address.toString());
}
if (isNameChanged(toUpdate.getName(), name)) {
toUpdate.setName(name);
}
if (isStatusUnknown(toUpdate.getUpdateStatus())) {
toUpdate.setUpdateStatus(TargetUpdateStatus.REGISTERED);
}
toUpdate.setLastTargetQuery(System.currentTimeMillis());
afterCommit.afterCommit(() -> eventPublisherHolder.getEventPublisher()
.publishEvent(new TargetPollEvent(toUpdate, eventPublisherHolder.getApplicationId())));
return targetRepository.save(toUpdate);
}
return toUpdate;
}
private boolean isStoreEager(final JpaTarget toUpdate, final URI address) {
if (repositoryProperties.isEagerPollPersistence()) {
return true;
} else if (toUpdate.getAddress() == null) {
return true;
} else {
return !toUpdate.getAddress().equals(address);
}
private boolean isStoreEager(final JpaTarget toUpdate, final URI address, final String name) {
return repositoryProperties.isEagerPollPersistence() || isAddressChanged(toUpdate.getAddress(), address)
|| isNameChanged(toUpdate.getName(), name) || isStatusUnknown(toUpdate.getUpdateStatus());
}
private boolean isAddressChanged(final URI addressToUpdate, final URI address) {
return addressToUpdate == null || !addressToUpdate.equals(address);
}
private boolean isNameChanged(final String nameToUpdate, final String name) {
return StringUtils.hasText(name) && !nameToUpdate.equals(name);
}
private boolean isStatusUnknown(final TargetUpdateStatus statusToUpdate) {
return TargetUpdateStatus.UNKNOWN == statusToUpdate;
}
@Override
@@ -596,8 +605,8 @@ public class JpaControllerManagement implements ControllerManagement {
* ActionStatus updates are allowed mainly if the action is active. If the
* action is not active we accept further status updates if permitted so by
* repository configuration. In this case, only the values: Status.ERROR and
* Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we
* accept status updates only once.
* Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we accept
* status updates only once.
*/
private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) {
@@ -732,8 +741,8 @@ public class JpaControllerManagement implements ControllerManagement {
final UpdateMode mode) {
/*
* Constraints on attribute keys & values are not validated by
* EclipseLink. Hence, they are validated here.
* Constraints on attribute keys & values are not validated by EclipseLink.
* Hence, they are validated here.
*/
if (data.entrySet().stream().anyMatch(e -> !isAttributeEntryValid(e))) {
throw new InvalidTargetAttributeException();
@@ -744,7 +753,6 @@ public class JpaControllerManagement implements ControllerManagement {
// get the modifiable attribute map
final Map<String, String> controllerAttributes = target.getControllerAttributes();
final UpdateMode updateMode = mode != null ? mode : UpdateMode.MERGE;
switch (updateMode) {
case REMOVE:
@@ -811,8 +819,8 @@ public class JpaControllerManagement implements ControllerManagement {
}
/**
* Registers retrieved status for given {@link Target} and {@link Action} if
* it does not exist yet.
* Registers retrieved status for given {@link Target} and {@link Action} if it
* does not exist yet.
*
* @param actionId
* to the handle status for