Skip to content

Commit

Permalink
remove status from update workflow instance rest api, set status base…
Browse files Browse the repository at this point in the history
…d on state type
  • Loading branch information
Edvard Fonsell committed Apr 14, 2015
1 parent dab55d7 commit 2cad488
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import static com.nitorcreations.nflow.engine.workflow.definition.NextAction.moveToState;
import static com.nitorcreations.nflow.engine.workflow.definition.NextAction.stopInState;
import static com.nitorcreations.nflow.engine.workflow.definition.WorkflowStateType.manual;
import static com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus.executing;
import static com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus.finished;
import static com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus.inProgress;
import static com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstanceAction.WorkflowActionType.stateExecution;
import static com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstanceAction.WorkflowActionType.stateExecutionFailed;
Expand Down Expand Up @@ -182,13 +180,7 @@ private WorkflowInstanceStatus getStatus(StateExecutionImpl execution, WorkflowS
if (isNextActivationImmediately(execution)) {
return executing;
}
if (nextState.getType() == manual) {
return WorkflowInstanceStatus.manual;
}
if (nextState.getType().isFinal()) {
return finished;
}
return inProgress;
return nextState.getType().getStatus();
}

private WorkflowActionType getActionType(StateExecutionImpl execution) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.nitorcreations.nflow.engine.workflow.definition.WorkflowDefinition;
import com.nitorcreations.nflow.engine.workflow.instance.QueryWorkflowInstances;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstanceAction;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstanceAction.WorkflowActionType;

Expand Down Expand Up @@ -72,6 +73,9 @@ public int insertWorkflowInstance(WorkflowInstance instance) {
if (isEmpty(instance.externalId)) {
builder.setExternalId(UUID.randomUUID().toString());
}
if (instance.status == null) {
builder.setStatus(WorkflowInstanceStatus.created);
}
int id = workflowInstanceDao.insertWorkflowInstance(builder.build());
if (id == -1 && !isEmpty(instance.externalId)) {
QueryWorkflowInstances query = new QueryWorkflowInstances.Builder().addTypes(def.getType()).setExternalId(instance.externalId).build();
Expand All @@ -82,24 +86,34 @@ public int insertWorkflowInstance(WorkflowInstance instance) {

/**
* Update the workflow instance in the database if it is currently not running, and insert the workflow instance action. If
* action is null, it will be automatically created.
* action is null, it will be automatically created. If the state of the instance is not null, the status of the instance is
* updated based on the new state. If the state of the instance is null, neither state nor status are updated.
* @param instance The instance to be updated.
* @param action The action to be inserted. Can be null.
* @return True if the update was successful, false otherwise.
*/
@Transactional
public boolean updateWorkflowInstance(WorkflowInstance instance, WorkflowInstanceAction action) {
boolean updated = workflowInstanceDao.updateNotRunningWorkflowInstance(instance);
WorkflowInstance.Builder builder = new WorkflowInstance.Builder(instance);
if (instance.state == null) {
builder.setStatus(null);
} else {
String type = workflowInstanceDao.getWorkflowInstance(instance.id).type;
WorkflowDefinition<?> definition = workflowDefinitionService.getWorkflowDefinition(type);
builder.setStatus(definition.getState(instance.state).getType().getStatus());
}
WorkflowInstance updatedInstance = builder.build();
boolean updated = workflowInstanceDao.updateNotRunningWorkflowInstance(updatedInstance);
if (updated) {
WorkflowInstanceAction.Builder actionBuilder;
if (action == null) {
actionBuilder = new WorkflowInstanceAction.Builder().setWorkflowInstanceId(instance.id).setStateText("N/A");
actionBuilder = new WorkflowInstanceAction.Builder().setWorkflowInstanceId(updatedInstance.id).setStateText("N/A");
} else {
actionBuilder = new WorkflowInstanceAction.Builder(action);
}
String currentState = workflowInstanceDao.getWorkflowInstanceState(instance.id);
String currentState = workflowInstanceDao.getWorkflowInstanceState(updatedInstance.id);
action = actionBuilder.setState(currentState).build();
workflowInstanceDao.insertWorkflowInstanceAction(instance, action);
workflowInstanceDao.insertWorkflowInstanceAction(updatedInstance, action);
}
return updated;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.nitorcreations.nflow.engine.workflow.definition;

import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus;

/**
* Workflow state types.
*/
Expand All @@ -8,27 +10,29 @@ public enum WorkflowStateType {
/**
* Initial states of the workflow.
*/
start(false),
start(false, WorkflowInstanceStatus.inProgress),

This comment has been minimized.

Copy link
@jsyrjala

jsyrjala Apr 14, 2015

Member

Add comment why inProgress here and not created. (status value is set for instance when state is changed via API and not normal processing)


/**
* State that requires manual action. Workflow execution is stopped.
*/
manual(true),
manual(true, WorkflowInstanceStatus.manual),

/**
* State that can be normally executed.
*/
normal(false),
normal(false, WorkflowInstanceStatus.inProgress),

/**
* Final state of the workflow. Workflow execution is stopped.
*/
end(true);
end(true, WorkflowInstanceStatus.finished);

private final boolean isFinal;
private WorkflowInstanceStatus status;

private WorkflowStateType(boolean isFinal) {
private WorkflowStateType(boolean isFinal, WorkflowInstanceStatus status) {
this.isFinal = isFinal;
this.status = status;
}

/**
Expand All @@ -42,4 +46,14 @@ private WorkflowStateType(boolean isFinal) {
public boolean isFinal() {
return isFinal;
}

/**
* Returns the status for this type. This is used when a workflow instance state is updated, the new status of the instance will
* be determined based on the new state type.
*
* @return Default status for this state type.
*/
public WorkflowInstanceStatus getStatus() {
return status;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public static class Builder {

Integer id;
Integer executorId;
WorkflowInstanceStatus status = WorkflowInstanceStatus.created;
WorkflowInstanceStatus status;
String type;
String businessKey;
String externalId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,8 @@ public void fakePostgreSQLinsertWorkflowInstance() {
when(j.queryForObject(sql.capture(), eq(Integer.class), args.capture())).thenReturn(42);

DateTime started = DateTime.now();
WorkflowInstance wf = new WorkflowInstance.Builder().setState("updateState").setStateText("update text")
.setNextActivation(started.plusSeconds(1)).setRetries(3).setId(43).putStateVariable("A", "B")
WorkflowInstance wf = new WorkflowInstance.Builder().setStatus(inProgress).setState("updateState")
.setStateText("update text").setNextActivation(started.plusSeconds(1)).setRetries(3).setId(43).putStateVariable("A", "B")
.putStateVariable("C", "D").build();

d.insertWorkflowInstance(wf);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.joda.time.DateTime.now;
import static org.joda.time.DateTimeUtils.currentTimeMillis;
import static org.joda.time.DateTimeUtils.setCurrentMillisFixed;
import static org.joda.time.DateTimeUtils.setCurrentMillisSystem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
Expand All @@ -38,6 +38,7 @@
import com.nitorcreations.nflow.engine.workflow.definition.WorkflowDefinition;
import com.nitorcreations.nflow.engine.workflow.instance.QueryWorkflowInstances;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstance.WorkflowInstanceStatus;
import com.nitorcreations.nflow.engine.workflow.instance.WorkflowInstanceAction;

public class WorkflowInstanceServiceTest extends BaseNflowTest {
Expand Down Expand Up @@ -121,6 +122,14 @@ public void insertWorkflowCreatesMissingExternalId() {
assertThat(stored.getValue().externalId, notNullValue());
}

@Test
public void insertWorkflowSetsStatusToCreatedWhenStatusIsNotSpecified() {
WorkflowInstance i = constructWorkflowInstanceBuilder().setStatus(null).build();
when(workflowInstanceDao.insertWorkflowInstance(stored.capture())).thenReturn(42);
service.insertWorkflowInstance(i);
assertThat(stored.getValue().status, is(WorkflowInstanceStatus.created));
}

@Test(expected = RuntimeException.class)
public void insertWorkflowInstanceUnsupportedType() {
WorkflowInstance i = constructWorkflowInstanceBuilder().setType("nonexistent").build();
Expand All @@ -132,9 +141,25 @@ public void updateWorkflowInstanceWorks() {
WorkflowInstance i = constructWorkflowInstanceBuilder().setId(42).build();
WorkflowInstanceAction a = new WorkflowInstanceAction.Builder().setType(externalChange).setWorkflowInstanceId(i.id).build();
when(workflowInstanceDao.getWorkflowInstanceState(i.id)).thenReturn("currentState");
when(workflowInstanceDao.updateNotRunningWorkflowInstance(i)).thenReturn(true);
when(workflowInstanceDao.updateNotRunningWorkflowInstance(any(WorkflowInstance.class))).thenReturn(true);
when(workflowInstanceDao.getWorkflowInstance(42)).thenReturn(i);
assertThat(service.updateWorkflowInstance(i, a), is(true));
verify(workflowInstanceDao).updateNotRunningWorkflowInstance(stored.capture());
assertThat(stored.getValue().status, is(WorkflowInstanceStatus.inProgress));
verify(workflowInstanceDao).insertWorkflowInstanceAction(stored2.capture(), storedAction.capture());
assertThat(storedAction.getValue().state, is("currentState"));
}

@Test
public void updateWorkflowInstanceWorksWhenStateIsNull() {
WorkflowInstance i = constructWorkflowInstanceBuilder().setId(42).setState(null).build();
WorkflowInstanceAction a = new WorkflowInstanceAction.Builder().setType(externalChange).setWorkflowInstanceId(i.id).build();
when(workflowInstanceDao.getWorkflowInstanceState(i.id)).thenReturn("currentState");
when(workflowInstanceDao.updateNotRunningWorkflowInstance(any(WorkflowInstance.class))).thenReturn(true);
assertThat(service.updateWorkflowInstance(i, a), is(true));
verify(workflowInstanceDao).insertWorkflowInstanceAction(eq(i), storedAction.capture());
verify(workflowInstanceDao).updateNotRunningWorkflowInstance(stored.capture());
assertThat(stored.getValue().status, is(nullValue()));
verify(workflowInstanceDao).insertWorkflowInstanceAction(stored2.capture(), storedAction.capture());
assertThat(storedAction.getValue().state, is("currentState"));
}

Expand All @@ -143,6 +168,7 @@ public void updateRunningWorkflowInstanceFails() {
WorkflowInstance i = constructWorkflowInstanceBuilder().setId(42).build();
WorkflowInstanceAction a = new WorkflowInstanceAction.Builder().setType(externalChange).build();
when(workflowInstanceDao.updateNotRunningWorkflowInstance(i)).thenReturn(false);
when(workflowInstanceDao.getWorkflowInstance(42)).thenReturn(i);
assertThat(service.updateWorkflowInstance(i, a), is(false));
verify(workflowInstanceDao, never()).insertWorkflowInstanceAction(any(WorkflowInstance.class),
any(WorkflowInstanceAction.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,6 @@ public Response updateWorkflowInstance(@ApiParam("Internal id for workflow insta
msg += "API changed nextActivationTime to " + req.nextActivationTime + ". ";
}
}
if (req.status != null) {
builder.setStatus(WorkflowInstanceStatus.valueOf(req.status));
if (isBlank(req.actionDescription)) {
msg += "API changed status to " + req.status + ".";
}
}
if (msg.isEmpty()) {
return noContent().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,4 @@ public class UpdateWorkflowInstanceRequest {

@ApiModelProperty(value = "Description of the action", required = false)
public String actionDescription;

@ApiModelProperty(value = "New status of the workflow instance", required = false, allowableValues = "created,executing,inProgress,finished,manual,stopped")
public String status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ public void whenUpdatingStateUpdateWorkflowInstanceWorks() {
UpdateWorkflowInstanceRequest req = new UpdateWorkflowInstanceRequest();
req.state = "newState";
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance((WorkflowInstance) argThat(hasField("state", equalTo(req.state))),
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(allOf(hasField("state", equalTo(req.state)), hasField("status", equalTo(null)))),
(WorkflowInstanceAction) argThat(hasField("stateText", equalTo("API changed state to newState."))));
}

Expand All @@ -97,7 +98,7 @@ public void whenUpdatingStateWithDescriptionUpdateWorkflowInstanceWorks() {
req.actionDescription = "description";
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(hasField("state", equalTo(req.state))),
(WorkflowInstance) argThat(allOf(hasField("state", equalTo(req.state)), hasField("status", equalTo(null)))),
(WorkflowInstanceAction) argThat(allOf(hasField("stateText", equalTo("description")), hasField("type", equalTo(externalChange)))));
}

Expand All @@ -108,7 +109,7 @@ public void whenUpdatingNextActivationTimeUpdateWorkflowInstanceWorks() {
req.nextActivationTime = new DateTime(2014,11,12,17,55,0);
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(hasField("state", equalTo(null))),
(WorkflowInstance) argThat(allOf(hasField("state", equalTo(null)), hasField("status", equalTo(null)))),
(WorkflowInstanceAction) argThat(allOf(hasField("stateText", equalTo("API changed nextActivationTime to "
+ req.nextActivationTime + ".")), hasField("type", equalTo(externalChange)))));
}
Expand All @@ -121,35 +122,10 @@ public void whenUpdatingNextActivationTimeWithDescriptionUpdateWorkflowInstanceW
req.actionDescription = "description";
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(hasField("state", equalTo(null))),
(WorkflowInstance) argThat(allOf(hasField("state", equalTo(null)), hasField("status", equalTo(null)))),
(WorkflowInstanceAction) argThat(allOf(hasField("stateText", equalTo("description")), hasField("type", equalTo(externalChange)))));
}

@Test
public void whenUpdatingStatusUpdateWorkflowInstanceWorks() {
when(workflowInstances.getWorkflowInstance(3)).thenReturn(i);
UpdateWorkflowInstanceRequest req = new UpdateWorkflowInstanceRequest();
req.status = "finished";
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(hasField("status", equalTo(WorkflowInstanceStatus.finished))),
(WorkflowInstanceAction) argThat(allOf(hasField("stateText", equalTo("API changed status to finished.")),
hasField("type", equalTo(externalChange)))));
}

@Test
public void whenUpdatingStatusWithDescriptionUpdateWorkflowInstanceWorks() {
when(workflowInstances.getWorkflowInstance(3)).thenReturn(i);
UpdateWorkflowInstanceRequest req = new UpdateWorkflowInstanceRequest();
req.status = "finished";
req.actionDescription = "description";
resource.updateWorkflowInstance(3, req);
verify(workflowInstances).updateWorkflowInstance(
(WorkflowInstance) argThat(hasField("status", equalTo(WorkflowInstanceStatus.finished))),
(WorkflowInstanceAction) argThat(allOf(hasField("stateText", equalTo("description")),
hasField("type", equalTo(externalChange)))));
}

@Test
public void stoppingWorkflowInstanceWorks() {
when(workflowInstances.stopWorkflowInstance(3, "test", externalChange)).thenReturn(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ public void t03_moveToGrantLoanState() {
UpdateWorkflowInstanceRequest ureq = new UpdateWorkflowInstanceRequest();
ureq.nextActivationTime = now();
ureq.state = "grantLoan";
ureq.status = "inProgress";
fromClient(workflowInstanceResource, true).path(resp.id).put(ureq);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public void t03_moveToGrantLoanState() {
UpdateWorkflowInstanceRequest ureq = new UpdateWorkflowInstanceRequest();
ureq.nextActivationTime = now();
ureq.state = "grantLoan";
ureq.status = "inProgress";
Response response = fromClient(workflowInstanceResource, true).path(resp.id).put(ureq);
assertThat(response.getStatusInfo().getFamily(), is(Family.SUCCESSFUL));
}
Expand Down

0 comments on commit 2cad488

Please sign in to comment.