Merge pull request #35 from myrle-krantz/develop

task instances are now finished.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
index 496bd2d..beea82f 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/PortfolioManager.java
@@ -329,6 +329,7 @@
           produces = MediaType.ALL_VALUE,
           consumes = MediaType.APPLICATION_JSON_VALUE
   )
+  @ThrowsException(status = HttpStatus.CONFLICT, exception = TaskExecutionBySameUserAsCaseCreation.class)
   void markTaskExecution(@PathVariable("productidentifier") final String productIdentifier,
                          @PathVariable("caseidentifier") final String caseIdentifier,
                          @PathVariable("taskidentifier") final String taskIdentifier,
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductAlreadyExistsException.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductAlreadyExistsException.java
index 8bd6481..78233d9 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductAlreadyExistsException.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductAlreadyExistsException.java
@@ -18,6 +18,5 @@
 /**
  * @author Myrle Krantz
  */
-@SuppressWarnings("WeakerAccess")
 public class ProductAlreadyExistsException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductDefinitionIncomplete.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductDefinitionIncomplete.java
index 69d1f29..4ddefb5 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductDefinitionIncomplete.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductDefinitionIncomplete.java
@@ -18,6 +18,5 @@
 /**
  * @author Myrle Krantz
  */
-@SuppressWarnings("WeakerAccess")
 public class ProductDefinitionIncomplete extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductInUseException.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductInUseException.java
index 3b90749..d2c94f1 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductInUseException.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/ProductInUseException.java
@@ -18,6 +18,5 @@
 /**
  * @author Myrle Krantz
  */
-@SuppressWarnings("unused")
 public class ProductInUseException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/client/TaskExecutionBySameUserAsCaseCreation.java b/api/src/main/java/io/mifos/portfolio/api/v1/client/TaskExecutionBySameUserAsCaseCreation.java
new file mode 100644
index 0000000..f4de44f
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/client/TaskExecutionBySameUserAsCaseCreation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.portfolio.api.v1.client;
+
+/**
+ * @author Myrle Krantz
+ */
+public class TaskExecutionBySameUserAsCaseCreation extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/events/EventConstants.java b/api/src/main/java/io/mifos/portfolio/api/v1/events/EventConstants.java
index 7a0550f..9412d57 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/events/EventConstants.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/events/EventConstants.java
@@ -34,6 +34,7 @@
   String DELETE_TASK_DEFINITION = "delete-task-definition";
   String POST_CHARGE_DEFINITION = "post-charge-definition";
   String PUT_TASK_INSTANCE = "put-task-instance";
+  String PUT_TASK_INSTANCE_EXECUTION = "put-task-instance-execution";
   String PUT_CHARGE_DEFINITION = "put-charge-definition";
   String DELETE_PRODUCT_CHARGE_DEFINITION = "delete-product-charge-definition";
   String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
@@ -47,6 +48,7 @@
   String SELECTOR_PUT_TASK_DEFINITION = SELECTOR_NAME + " = '" + PUT_TASK_DEFINITION + "'";
   String SELECTOR_DELETE_TASK_DEFINITION = SELECTOR_NAME + " = '" + DELETE_TASK_DEFINITION + "'";
   String SELECTOR_PUT_TASK_INSTANCE = SELECTOR_NAME + " = '" + PUT_TASK_INSTANCE + "'";
+  String SELECTOR_PUT_TASK_INSTANCE_EXECUTION = SELECTOR_NAME + " = '" + PUT_TASK_INSTANCE_EXECUTION + "'";
   String SELECTOR_POST_CHARGE_DEFINITION = SELECTOR_NAME + " = '" + POST_CHARGE_DEFINITION + "'";
   String SELECTOR_PUT_CHARGE_DEFINITION = SELECTOR_NAME + " = '" + PUT_CHARGE_DEFINITION + "'";
   String SELECTOR_DELETE_PRODUCT_CHARGE_DEFINITION = SELECTOR_NAME + " = '" + DELETE_PRODUCT_CHARGE_DEFINITION + "'";
diff --git a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
index efca4f2..9e07c3b 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
@@ -270,7 +270,7 @@
     ret.setName("feep");
     ret.setMandatory(false);
     ret.setActions(new HashSet<>());
-    ret.setFourEyes(true);
+    ret.setFourEyes(false);
     return ret;
   }
 
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
index ce838b5..f5e446c 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestTaskInstances.java
@@ -15,11 +15,16 @@
  */
 package io.mifos.portfolio;
 
+import io.mifos.core.api.context.AutoUserContext;
+import io.mifos.core.api.util.NotFoundException;
+import io.mifos.core.test.domain.TimeStampChecker;
+import io.mifos.portfolio.api.v1.client.TaskExecutionBySameUserAsCaseCreation;
 import io.mifos.portfolio.api.v1.domain.Case;
 import io.mifos.portfolio.api.v1.domain.Product;
 import io.mifos.portfolio.api.v1.domain.TaskDefinition;
 import io.mifos.portfolio.api.v1.domain.TaskInstance;
 import io.mifos.portfolio.api.v1.events.EventConstants;
+import io.mifos.portfolio.api.v1.events.TaskDefinitionEvent;
 import io.mifos.portfolio.api.v1.events.TaskInstanceEvent;
 import org.junit.Assert;
 import org.junit.Test;
@@ -64,4 +69,105 @@
     taskInstance.setComment("And the words of the prophets are written on the subway walls");
     Assert.assertEquals(taskInstance, taskInstanceChanged);
   }
+
+  @Test
+  public void shouldMarkBasicTaskExecuted() throws InterruptedException {
+    final Product product = createProduct();
+    final TaskDefinition taskDefinition = createTaskDefinition(product);
+
+    enableProduct(product);
+
+    final Case customerCase = createCase(product.getIdentifier());
+
+    final TaskInstance taskInstance = portfolioManager.getTaskForCase(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier());
+
+    final TimeStampChecker timeStampChecker = TimeStampChecker.roughlyNow();
+    portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(),  taskDefinition.getIdentifier(), true);
+    Assert.assertTrue(eventRecorder.wait(EventConstants.PUT_TASK_INSTANCE_EXECUTION, new TaskInstanceEvent(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier())));
+
+    final TaskInstance executedTaskInstance = portfolioManager.getTaskForCase(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier());
+    timeStampChecker.assertCorrect(executedTaskInstance.getExecutedOn());
+    Assert.assertEquals(TEST_USER, executedTaskInstance.getExecutedBy());
+
+    final List<TaskInstance> tasksForCaseExcludingExecuted = portfolioManager.getAllTasksForCase(product.getIdentifier(), customerCase.getIdentifier(), false);
+    Assert.assertFalse(tasksForCaseExcludingExecuted.contains(taskInstance));
+
+    final List<TaskInstance> allTasksForCase = portfolioManager.getAllTasksForCase(product.getIdentifier(), customerCase.getIdentifier(), true);
+    Assert.assertTrue(allTasksForCase.contains(executedTaskInstance));
+  }
+
+  @Test
+  public void shouldMarkBasicTaskNotExecuted() throws InterruptedException {
+    final Product product = createProduct();
+    final TaskDefinition taskDefinition = createTaskDefinition(product);
+
+    enableProduct(product);
+
+    final Case customerCase = createCase(product.getIdentifier());
+
+    portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(),  taskDefinition.getIdentifier(), true);
+    Assert.assertTrue(eventRecorder.wait(EventConstants.PUT_TASK_INSTANCE_EXECUTION, new TaskInstanceEvent(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier())));
+
+    final TaskInstance executedTaskInstance = portfolioManager.getTaskForCase(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier());
+    Assert.assertNotNull(executedTaskInstance.getExecutedBy());
+    Assert.assertNotNull(executedTaskInstance.getExecutedOn());
+
+    portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(),  taskDefinition.getIdentifier(), false);
+    Assert.assertTrue(eventRecorder.wait(EventConstants.PUT_TASK_INSTANCE_EXECUTION, new TaskInstanceEvent(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier())));
+
+    final TaskInstance unExecutedTaskInstance = portfolioManager.getTaskForCase(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier());
+    Assert.assertNull(unExecutedTaskInstance.getExecutedOn());
+    Assert.assertNull(unExecutedTaskInstance.getExecutedBy());
+
+    final List<TaskInstance> tasksForCaseExcludingExecuted = portfolioManager.getAllTasksForCase(product.getIdentifier(), customerCase.getIdentifier(), false);
+    Assert.assertTrue(tasksForCaseExcludingExecuted.contains(unExecutedTaskInstance));
+  }
+
+  @Test(expected = NotFoundException.class)
+  public void shouldFailToMarkNonExistantTask() throws InterruptedException {
+    final Product product = createProduct();
+    createTaskDefinition(product);
+
+    enableProduct(product);
+
+    final Case customerCase = createCase(product.getIdentifier());
+
+    portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(),  "blubble", true);
+  }
+
+
+  @Test(expected = TaskExecutionBySameUserAsCaseCreation.class)
+  public void fourEyesCannotBeMarkedByCaseCreator() throws InterruptedException {
+    final Product product = createProduct();
+
+    final TaskDefinition taskDefinition = createTaskDefinition(product);
+    taskDefinition.setFourEyes(true);
+    portfolioManager.changeTaskDefinition(product.getIdentifier(), taskDefinition.getIdentifier(), taskDefinition);
+    eventRecorder.wait(EventConstants.PUT_TASK_DEFINITION, new TaskDefinitionEvent(product.getIdentifier(), taskDefinition.getIdentifier()));
+
+    enableProduct(product);
+
+    final Case customerCase = createCase(product.getIdentifier());
+
+    portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(),  taskDefinition.getIdentifier(), true);
+  }
+
+
+  @Test
+  public void fourEyesCanBeMarkedByDifferentUser() throws InterruptedException {
+    final Product product = createProduct();
+
+    final TaskDefinition taskDefinition = createTaskDefinition(product);
+    taskDefinition.setFourEyes(true);
+    portfolioManager.changeTaskDefinition(product.getIdentifier(), taskDefinition.getIdentifier(), taskDefinition);
+    eventRecorder.wait(EventConstants.PUT_TASK_DEFINITION, new TaskDefinitionEvent(product.getIdentifier(), taskDefinition.getIdentifier()));
+
+    enableProduct(product);
+
+    final Case customerCase = createCase(product.getIdentifier());
+
+    try (final AutoUserContext ignored = this.tenantApplicationSecurityEnvironment.createAutoUserContext("fred")) {
+      portfolioManager.markTaskExecution(product.getIdentifier(), customerCase.getIdentifier(), taskDefinition.getIdentifier(), true);
+    }
+  }
 }
diff --git a/component-test/src/main/java/io/mifos/portfolio/listener/TaskInstanceEventListener.java b/component-test/src/main/java/io/mifos/portfolio/listener/TaskInstanceEventListener.java
index 6f01215..80baf69 100644
--- a/component-test/src/main/java/io/mifos/portfolio/listener/TaskInstanceEventListener.java
+++ b/component-test/src/main/java/io/mifos/portfolio/listener/TaskInstanceEventListener.java
@@ -45,7 +45,17 @@
       selector = EventConstants.SELECTOR_PUT_TASK_INSTANCE
   )
   public void onChangeTaskInstance(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
-                                     final String payload) {
+                                   final String payload) {
     this.eventRecorder.event(tenant, EventConstants.PUT_TASK_INSTANCE, payload, TaskInstanceEvent.class);
   }
+
+  @JmsListener(
+      subscription = EventConstants.DESTINATION,
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_PUT_TASK_INSTANCE_EXECUTION
+  )
+  public void onChangeTaskInstanceE(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                                   final String payload) {
+    this.eventRecorder.event(tenant, EventConstants.PUT_TASK_INSTANCE_EXECUTION, payload, TaskInstanceEvent.class);
+  }
 }
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java b/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java
index a1e13f7..e9d740f 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/command/ExecuteTaskInstanceCommand.java
@@ -31,6 +31,22 @@
     this.executed = executed;
   }
 
+  public String getProductIdentifier() {
+    return productIdentifier;
+  }
+
+  public String getCaseIdentifier() {
+    return caseIdentifier;
+  }
+
+  public String getTaskIdentifier() {
+    return taskIdentifier;
+  }
+
+  public Boolean getExecuted() {
+    return executed;
+  }
+
   @Override
   public String toString() {
     return "ExecuteTaskInstanceCommand{" +
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/TaskInstanceCommandHandler.java b/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/TaskInstanceCommandHandler.java
index c7c26fc..5e32df0 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/TaskInstanceCommandHandler.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/command/handler/TaskInstanceCommandHandler.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.portfolio.service.internal.command.handler;
 
+import io.mifos.core.api.util.UserContextHolder;
 import io.mifos.core.command.annotation.Aggregate;
 import io.mifos.core.command.annotation.CommandHandler;
 import io.mifos.core.command.annotation.CommandLogLevel;
@@ -24,11 +25,15 @@
 import io.mifos.portfolio.api.v1.events.EventConstants;
 import io.mifos.portfolio.api.v1.events.TaskInstanceEvent;
 import io.mifos.portfolio.service.internal.command.ChangeTaskInstanceCommand;
+import io.mifos.portfolio.service.internal.command.ExecuteTaskInstanceCommand;
 import io.mifos.portfolio.service.internal.mapper.TaskInstanceMapper;
 import io.mifos.portfolio.service.internal.repository.TaskInstanceEntity;
 import io.mifos.portfolio.service.internal.repository.TaskInstanceRepository;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.time.Clock;
+import java.time.LocalDateTime;
+
 /**
  * @author Myrle Krantz
  */
@@ -63,4 +68,31 @@
         changeTaskInstanceCommand.getCaseIdentifier(),
         changeTaskInstanceCommand.getInstance().getTaskIdentifier());
   }
+
+  @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_TASK_INSTANCE_EXECUTION)
+  public TaskInstanceEvent process(final ExecuteTaskInstanceCommand changeTaskInstanceExecutionCommand) {
+    final String productIdentifier = changeTaskInstanceExecutionCommand.getProductIdentifier();
+    final String caseIdentifier = changeTaskInstanceExecutionCommand.getCaseIdentifier();
+    final String taskIdentifier = changeTaskInstanceExecutionCommand.getTaskIdentifier();
+    final boolean executed = changeTaskInstanceExecutionCommand.getExecuted();
+
+    final TaskInstanceEntity taskInstanceEntity
+        = taskInstanceRepository.findByProductIdAndCaseIdAndTaskId(productIdentifier, caseIdentifier, taskIdentifier)
+        .orElseThrow(() -> ServiceException.notFound("Task instance ''{0}.{1}.{2}'' not found.",
+            productIdentifier, caseIdentifier, taskIdentifier));
+
+    if (executed) {
+      taskInstanceEntity.setExecutedOn(LocalDateTime.now(Clock.systemUTC()));
+      taskInstanceEntity.setExecutedBy(UserContextHolder.checkedGetUser());
+    }
+    else {
+      taskInstanceEntity.setExecutedOn(null);
+      taskInstanceEntity.setExecutedBy(null);
+    }
+
+    taskInstanceRepository.save(taskInstanceEntity);
+
+    return new TaskInstanceEvent(productIdentifier, caseIdentifier, taskIdentifier);
+  }
 }
diff --git a/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java b/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java
index 2180b7e..001d60a 100644
--- a/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java
+++ b/service/src/main/java/io/mifos/portfolio/service/rest/TaskInstanceRestController.java
@@ -17,9 +17,12 @@
 
 import io.mifos.anubis.annotation.AcceptedTokenType;
 import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.api.util.UserContextHolder;
 import io.mifos.core.command.gateway.CommandGateway;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.portfolio.api.v1.PermittableGroupIds;
+import io.mifos.portfolio.api.v1.domain.Case;
+import io.mifos.portfolio.api.v1.domain.TaskDefinition;
 import io.mifos.portfolio.api.v1.domain.TaskInstance;
 import io.mifos.portfolio.service.internal.command.ChangeTaskInstanceCommand;
 import io.mifos.portfolio.service.internal.command.ExecuteTaskInstanceCommand;
@@ -71,7 +74,7 @@
                                         @PathVariable("caseidentifier") final String caseIdentifier,
                                         @RequestParam(value = "includeExecuted", required = false) final Boolean includeExecuted)
   {
-    checkCaseExists(productIdentifier, caseIdentifier);
+    checkedGetCase(productIdentifier, caseIdentifier);
 
     return taskInstanceService.findAllEntities(productIdentifier, caseIdentifier, includeExecuted);
   }
@@ -85,10 +88,10 @@
   )
   public @ResponseBody
   TaskInstance getTaskForCase(@PathVariable("productidentifier") final String productIdentifier,
-                 @PathVariable("caseidentifier") final String caseIdentifier,
-                 @PathVariable("taskidentifier") final String taskIdentifier)
+                              @PathVariable("caseidentifier") final String caseIdentifier,
+                              @PathVariable("taskidentifier") final String taskIdentifier)
   {
-    checkCaseExists(productIdentifier, caseIdentifier);
+    checkedGetCase(productIdentifier, caseIdentifier);
 
     return taskInstanceService.findByIdentifier(productIdentifier, caseIdentifier, taskIdentifier).orElseThrow(
         () -> ServiceException.notFound("No task instance ''{0}.{1}.{2}'' found.", productIdentifier, caseIdentifier, taskIdentifier));
@@ -107,9 +110,9 @@
                                          @PathVariable("taskidentifier") final String taskIdentifier,
                                          @RequestBody @Valid final TaskInstance instance)
   {
-    checkCaseExists(productIdentifier, caseIdentifier);
+    checkedGetCase(productIdentifier, caseIdentifier);
 
-    checkTaskDefinitionExists(productIdentifier, taskIdentifier);
+    checkedGetTaskDefinition(productIdentifier, taskIdentifier);
 
     if (!taskIdentifier.equals(instance.getTaskIdentifier()))
       throw ServiceException.badRequest("Instance identifiers may not be changed.");
@@ -132,21 +135,26 @@
                                          @PathVariable("taskidentifier") final String taskIdentifier,
                                          @RequestBody @Valid final Boolean executed)
   {
-    checkTaskDefinitionExists(productIdentifier, taskIdentifier);
+    final TaskDefinition taskDefinition = checkedGetTaskDefinition(productIdentifier, taskIdentifier);
+    if (taskDefinition.getFourEyes()) {
+      final Case customerCase = checkedGetCase(productIdentifier, caseIdentifier);
+      if (UserContextHolder.checkedGetUser().equals(customerCase.getCreatedBy()))
+        throw ServiceException.conflict("Signing user must be different than case creator.");
+    }
 
     commandGateway.process(new ExecuteTaskInstanceCommand(productIdentifier, caseIdentifier, taskIdentifier, executed));
 
     return ResponseEntity.accepted().build();
   }
 
-  private void checkTaskDefinitionExists(final String productIdentifier,
-                                         final String taskDefinitionIdentifier) throws ServiceException {
-    taskDefinitionService.findByIdentifier(productIdentifier, taskDefinitionIdentifier)
+  private TaskDefinition checkedGetTaskDefinition(final String productIdentifier,
+                                                  final String taskDefinitionIdentifier) throws ServiceException {
+    return taskDefinitionService.findByIdentifier(productIdentifier, taskDefinitionIdentifier)
         .orElseThrow(() -> ServiceException.notFound("No task with the identifier ''{0}.{1}'' exists.", productIdentifier, taskDefinitionIdentifier));
   }
 
-  private void checkCaseExists(final String productIdentifier, final String caseIdentifier) throws ServiceException {
-    caseService.findByIdentifier(productIdentifier, caseIdentifier)
-        .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{2}'' does not exist.", productIdentifier, caseIdentifier));
+  private Case checkedGetCase(final String productIdentifier, final String caseIdentifier) throws ServiceException {
+    return caseService.findByIdentifier(productIdentifier, caseIdentifier)
+        .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{1}'' does not exist.", productIdentifier, caseIdentifier));
   }
 }