Make entities immutable and create proper update methods that state by signature what can be updated. (#342)

Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
Kai Zimmermann
2016-11-17 20:07:23 +01:00
committed by GitHub
parent b6834e9ee2
commit ca63106d5c
314 changed files with 7699 additions and 6914 deletions

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.amqp;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -25,11 +26,11 @@ import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.RepositoryConstants;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.TenantNotExistException;
import org.eclipse.hawkbit.repository.exception.TooManyStatusEntriesException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.util.IpUtil;
import org.slf4j.Logger;
@@ -224,42 +225,66 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
final ActionUpdateStatus actionUpdateStatus = convertMessage(message, ActionUpdateStatus.class);
final Action action = checkActionExist(message, actionUpdateStatus);
final ActionStatus actionStatus = createActionStatus(message, actionUpdateStatus, action);
final List<String> messages = actionUpdateStatus.getMessage();
if (ArrayUtils.isNotEmpty(message.getMessageProperties().getCorrelationId())) {
messages.add(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id "
+ convertCorrelationId(message));
}
updateLastPollTime(action.getTarget());
final Status status = mapStatus(message, actionUpdateStatus, action);
final ActionStatusCreate actionStatus = entityFactory.actionStatus().create(action.getId()).status(status)
.messages(messages);
final Action addUpdateActionStatus = getUpdateActionStatus(status, actionStatus);
if (!addUpdateActionStatus.isActive()) {
lookIfUpdateAvailable(action.getTarget());
}
}
private Status mapStatus(final Message message, final ActionUpdateStatus actionUpdateStatus, final Action action) {
Status status = null;
switch (actionUpdateStatus.getActionStatus()) {
case DOWNLOAD:
actionStatus.setStatus(Status.DOWNLOAD);
status = Status.DOWNLOAD;
break;
case RETRIEVED:
actionStatus.setStatus(Status.RETRIEVED);
status = Status.RETRIEVED;
break;
case RUNNING:
actionStatus.setStatus(Status.RUNNING);
status = Status.RUNNING;
break;
case CANCELED:
actionStatus.setStatus(Status.CANCELED);
status = Status.CANCELED;
break;
case FINISHED:
actionStatus.setStatus(Status.FINISHED);
status = Status.FINISHED;
break;
case ERROR:
actionStatus.setStatus(Status.ERROR);
status = Status.ERROR;
break;
case WARNING:
actionStatus.setStatus(Status.WARNING);
status = Status.WARNING;
break;
case CANCEL_REJECTED:
handleCancelRejected(message, action, actionStatus);
status = hanldeCancelRejectedState(message, action);
break;
default:
logAndThrowMessageError(message, "Status for action does not exisit.");
}
final Action addUpdateActionStatus = getUpdateActionStatus(actionStatus);
return status;
}
if (!addUpdateActionStatus.isActive()) {
lookIfUpdateAvailable(action.getTarget());
private Status hanldeCancelRejectedState(final Message message, final Action action) {
if (action.isCancelingOrCanceled()) {
return Status.WARNING;
} else {
logAndThrowMessageError(message,
"Cancel recjected message is not allowed, if action is on state: " + action.getStatus());
return null;
}
}
@@ -267,27 +292,12 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
controllerManagement.updateTargetStatus(target.getTargetInfo(), null, System.currentTimeMillis(), null);
}
private ActionStatus createActionStatus(final Message message, final ActionUpdateStatus actionUpdateStatus,
final Action action) {
final ActionStatus actionStatus = entityFactory.generateActionStatus();
actionUpdateStatus.getMessage().forEach(actionStatus::addMessage);
if (ArrayUtils.isNotEmpty(message.getMessageProperties().getCorrelationId())) {
actionStatus.addMessage(RepositoryConstants.SERVER_MESSAGE_PREFIX + "DMF message correlation-id "
+ convertCorrelationId(message));
}
actionStatus.setAction(action);
actionStatus.setOccurredAt(System.currentTimeMillis());
return actionStatus;
}
private static String convertCorrelationId(final Message message) {
return new String(message.getMessageProperties().getCorrelationId(), StandardCharsets.UTF_8);
}
private Action getUpdateActionStatus(final ActionStatus actionStatus) {
if (actionStatus.getStatus().equals(Status.CANCELED)) {
private Action getUpdateActionStatus(final Status status, final ActionStatusCreate actionStatus) {
if (Status.CANCELED.equals(status)) {
return controllerManagement.addCancelActionStatus(actionStatus);
}
return controllerManagement.addUpdateActionStatus(actionStatus);
@@ -310,18 +320,4 @@ public class AmqpMessageHandlerService extends BaseAmqpService {
}
return action;
}
private static void handleCancelRejected(final Message message, final Action action,
final ActionStatus actionStatus) {
if (action.isCancelingOrCanceled()) {
actionStatus.setStatus(Status.WARNING);
// cancel action rejected, write warning status message and fall
// back to running action status
} else {
logAndThrowMessageError(message,
"Cancel recjected message is not allowed, if action is on state: " + action.getStatus());
}
}
}

View File

@@ -123,8 +123,7 @@ public class AmqpControllerAuthenticationTest {
final DdiSecurityProperties secruityProperties = mock(DdiSecurityProperties.class);
final Rp rp = mock(Rp.class);
final org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication ddiAuthentication = mock(
org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.class);
final DdiSecurityProperties.Authentication ddiAuthentication = mock(DdiSecurityProperties.Authentication.class);
final Anonymous anonymous = mock(Anonymous.class);
when(secruityProperties.getRp()).thenReturn(rp);
when(rp.getSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d");

View File

@@ -34,9 +34,7 @@ import org.eclipse.hawkbit.repository.SystemManagement;
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.CancelTargetAssignmentEvent;
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
@@ -93,9 +91,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
@Override
public void before() throws Exception {
super.before();
final Target generateTarget = entityFactory.generateTarget(CONTROLLER_ID, TEST_TOKEN);
generateTarget.getTargetInfo().setAddress(AMQP_URI.toString());
testTarget = targetManagement.createTarget(generateTarget);
testTarget = targetManagement.createTarget(entityFactory.target().create().controllerId(CONTROLLER_ID)
.securityToken(TEST_TOKEN).address(AMQP_URI.toString()));
this.rabbitTemplate = Mockito.mock(RabbitTemplate.class);
when(rabbitTemplate.getMessageConverter()).thenReturn(new Jackson2JsonMessageConverter());
@@ -121,15 +118,13 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
@Test
@Description("Verfies that download and install event with no software modul works")
public void testSendDownloadRequesWithEmptySoftwareModules() {
final Action action = createAction(
testdataFactory.createDistributionSetWithNoSoftwareModules(UUID.randomUUID().toString(), "1.0"));
final TargetAssignDistributionSetEvent targetAssignDistributionSetEvent = new TargetAssignDistributionSetEvent(
action, serviceMatcher.getServiceId());
"DEFAULT", 1L, 1L, CONTROLLER_ID, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, 1L);
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
assertTrue("No softwaremmodule should be contained in the request",
downloadAndUpdateRequest.getSoftwareModules().isEmpty());
@@ -142,14 +137,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
return sendMessage;
}
private JpaAction createAction(final DistributionSet testDs) {
final Action action = entityFactory.generateAction();
final JpaAction jpaAction = (JpaAction) action;
action.setDistributionSet(testDs);
action.setTarget(testTarget);
jpaAction.setActionType(ActionType.FORCED);
return actionRepository.save(jpaAction);
private Action createAction(final DistributionSet testDs) {
return deploymentManagement.findAction(assignDistributionSet(testDs, testTarget).getActions().get(0));
}
@Test
@@ -163,7 +152,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
action, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage,
action.getId());
assertThat(createDistributionSet.getModules()).hasSameSizeAs(downloadAndUpdateRequest.getSoftwareModules());
assertThat(downloadAndUpdateRequest.getTargetSecurityToken()).isEqualTo(TEST_TOKEN);
for (final org.eclipse.hawkbit.dmf.json.model.SoftwareModule softwareModule : downloadAndUpdateRequest
@@ -187,13 +177,14 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
@Test
@Description("Verfies that download and install event with software moduls and artifacts works")
public void testSendDownloadRequest() {
final DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
final SoftwareModule module = dsA.getModules().iterator().next();
DistributionSet dsA = testdataFactory.createDistributionSet(UUID.randomUUID().toString());
SoftwareModule module = dsA.getModules().iterator().next();
final List<DbArtifact> receivedList = new ArrayList<>();
for (final Artifact artifact : testdataFactory.createArtifacts(module.getId())) {
module.addArtifact(artifact);
receivedList.add(new DbArtifact());
}
module = softwareManagement.findSoftwareModuleById(module.getId());
dsA = distributionSetManagement.findDistributionSetById(dsA.getId());
final Action action = createAction(dsA);
@@ -203,7 +194,8 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
action, serviceMatcher.getServiceId());
amqpMessageDispatcherService.targetAssignDistributionSet(targetAssignDistributionSetEvent);
final Message sendMessage = getCaptureAdressEvent(targetAssignDistributionSetEvent);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage, action);
final DownloadAndUpdateRequest downloadAndUpdateRequest = assertDownloadAndInstallMessage(sendMessage,
action.getId());
assertEquals("DownloadAndUpdateRequest event should contains 3 software modules", 3,
downloadAndUpdateRequest.getSoftwareModules().size());
@@ -251,11 +243,11 @@ public class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
}
private DownloadAndUpdateRequest assertDownloadAndInstallMessage(final Message sendMessage, final Action action) {
private DownloadAndUpdateRequest assertDownloadAndInstallMessage(final Message sendMessage, final Long action) {
assertEventMessage(sendMessage);
final DownloadAndUpdateRequest downloadAndUpdateRequest = convertMessage(sendMessage,
DownloadAndUpdateRequest.class);
assertEquals(downloadAndUpdateRequest.getActionId(), action.getId());
assertEquals(downloadAndUpdateRequest.getActionId(), action);
assertEquals("The topic of the event shuold contain DOWNLOAD_AND_INSTALL", EventTopic.DOWNLOAD_AND_INSTALL,
sendMessage.getMessageProperties().getHeaders().get(MessageHeaderKey.TOPIC));
assertEquals("Security token of target", downloadAndUpdateRequest.getTargetSecurityToken(), TEST_TOKEN);

View File

@@ -40,16 +40,16 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource;
import org.eclipse.hawkbit.repository.ArtifactManagement;
import org.eclipse.hawkbit.repository.ControllerManagement;
import org.eclipse.hawkbit.repository.EntityFactory;
import org.eclipse.hawkbit.repository.builder.ActionStatusBuilder;
import org.eclipse.hawkbit.repository.builder.ActionStatusCreate;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
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.SecurityTokenGenerator;
@@ -359,7 +359,11 @@ public class AmqpMessageHandlerServiceTest {
final Action action = createActionWithTarget(22L, Status.FINISHED);
when(controllerManagementMock.findActionWithDetails(Matchers.any())).thenReturn(action);
when(controllerManagementMock.addUpdateActionStatus(Matchers.any())).thenReturn(action);
when(entityFactoryMock.generateActionStatus()).thenReturn(new JpaActionStatus());
final ActionStatusBuilder builder = mock(ActionStatusBuilder.class);
final ActionStatusCreate create = mock(ActionStatusCreate.class);
when(builder.create(22L)).thenReturn(create);
when(create.status(Matchers.any())).thenReturn(create);
when(entityFactoryMock.actionStatus()).thenReturn(builder);
// for the test the same action can be used
when(controllerManagementMock.findOldestActiveActionByTarget(Matchers.any())).thenReturn(Optional.of(action));
@@ -424,8 +428,8 @@ public class AmqpMessageHandlerServiceTest {
initalizeSecurityTokenGenerator();
// Mock
final JpaAction actionMock = mock(JpaAction.class);
final JpaTarget targetMock = mock(JpaTarget.class);
final Action actionMock = mock(Action.class);
final Target targetMock = mock(Target.class);
final TargetInfo targetInfoMock = mock(TargetInfo.class);
final DistributionSet distributionSetMock = mock(DistributionSet.class);