Menu

CreateTaskStateTransitionImpl

Arne Halvorsen

Implementing create task state transition

The type of state transition

The GPLS framework currently support two transition types :

  • operation state transition
  • property value change state transition

The inner class CreateTaskTransition is an operation state transition by extending the abstract OperationStateTransition An transition of this type is triggered by end user performing an operation typically by pushing a button or selecting an meny item, that sort of things. The state transition to be implemented here is the one of creating a new task.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#!/usr/bin/java
package org.aha.application.taskmanager.usecases;

import static org.aha.application.taskmanager.TaskDoneUtil.updateAfterTaskAddedOrRemoved;

import java.util.ResourceBundle;

import org.aha.application.taskmanager.data.ITaskRepository;
import org.aha.application.taskmanager.usecases.RemoveTaskUseCase.RemoveTaskTransition;
import org.aha.commons.ThrowIf;
import org.aha.gpls.viewmodel.DataViewModel;
import org.aha.gpls.viewmodel.PropertyParameters;
import org.aha.gpls.viewmodel.statemachine.OperationStateTransition;
import org.aha.gpls.viewmodel.statemachine.UseCase;

/**
 * <p>
 *   Use case for creating a task.
 * </p>
 */
public final class CreateTaskUseCase extends UseCase
{
    /**
     * <p>
     *   Constructor.
     * </p>
     * @param rep Interface to persistent task storage.
     */
    public CreateTaskUseCase(ITaskRepository rep)
    {   
        ThrowIf.isNull("rep", rep);

        // This use case has a single state transition that creates a task.
        addOperationTransition(new CreateTaskTransition(rep));
    }

    /**
     * <p>
     *   {@link OperationStateTransition} that create new task.
     * </p>
     */
    public static class CreateTaskTransition extends OperationStateTransition
    {
        private final ITaskRepository _rep;

        private CreateTaskTransition(ITaskRepository rep){ _rep=rep; }

        @Override
        public void transit(DataViewModel parentTask, ResourceBundle resources)
        {
            // In order to make a new task we need parent's id. It is an
            // integer and it is mandatory for a task to have this property
            // so ask for a Integer type value explicit and use the 
            // 'mandatory' method which will throw an exception if view model
            // representing the parent missing id property.
            Integer pid=parentTask.getMandatoryPropertyValue(Integer.class,
                "id");

            // Having the id of the parent can ask repository to create new
            // task.
            Integer sid=_rep.createSubTask(pid);

            // If we are here new task has been successfully created and we
            // must update the view model graph to reflect this fact:

            // First create a view model to represent the new task.
            DataViewModel subTask=parentTask.createChild();

            // Parameter to setProperty methods telling views not to expose
            // property to end user.
            PropertyParameters notExposed=new PropertyParameters()
                .exposed(false);

            // Sets the property of the new task:

            // The id property is for code only so third tell views not to
            // expose this property to end user (default is to expose).
            subTask.setProperty("id", sid, notExposed);  

            // All tasks has a name property of string type but for a new task 
            // it is unassigned.
            subTask.setProperty("name", String.class); 

            // All tasks has a boolean property telling if a task is done or
            // not. A newly created task is 'not done'.
            subTask.setProperty("done", false);

            // Tells which operations end user can do related to created task.

            // Can create a sub task (do what we do here :-)
            subTask.addOperation(CreateTaskTransition.class);

            // Can remove it.
            subTask.addOperation(RemoveTaskTransition.class);

            // The new task may have changed state of ancestors in hierarchy;
            // the 'updateAfterTaskAddedOrRemoved' algorithm will do needed
            // updates.
            updateAfterTaskAddedOrRemoved(parentTask);
        }

    }

}

Implementation

Implementation of the state transition is to implement the virtual method transit (line 49) that accepts two parameters:

  • A DataViewModel: An operation is always associated with a DataViewModel and this parameter is that object. In this case it is the view model that represents the parent task of the new task.
  • Resources: ResourceBundle with application specific resources for i18n and possible other uses.

The transit method here does:

  • Use an injected repository to create the task (line 61) given the parent of new task's id. Parent id is a property of the parent task named 'id' (line 56).
  • After the repository has succesfully created a task the state of the view model graph must be updated to this fact (line 63 to 99). See inline comments in source code above for details.

Adding the state transition to the state machine

State transitions are collected in use cases. In this case the use case (CreateTaskUseCase) consist only of one transition, in general an use case can have several transitions of different types that natural belong together.

The code that configure the application passes an instance of the use case to the state machine that is to drive the application. The use case for creating a task is added to the state machine in the task manager application's main method listed below (line 11).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/java
public static void main(String[] args)
{
    ITaskRepository rep=getTaskRepository();

    DataViewModel initialState=getInitialState(args, rep);
    ResourceBundle resources=getResources(args);

    new PresentationLayer(
        new StateMachine(initialState)
          .addUseCase(new CreateTaskUseCase(rep))
          .addUseCase(new RemoveTaskUseCase(rep))
          .addUseCase(new ChangeTaskDoneStatusUseCase(rep)),
        resources);
}

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.