Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement status transitions for an Entity in java?

I have multiple entities in my application like Users, Accounts, Licenses etc. Each entity has a status associated with it like Active, Ok, Suspended, Unverified, PendingPayment, PendingApproval etc. I want to make sure the entities can move from a predefined status to another like User can only move from Ok to Suspended but not from Unverified to Suspended. What would be the best design pattern to implement this ? I have looked around and mostly find state machines for such problems, but they look too complex for this as I don't want to consider events in the state. All I want to restrict is the transition of states.

As of now, I can think of using a pre-populated 2D array that defines all statuses in each dimension and represents possible transitions. Looking for any better approaches.

like image 549
TechCrunch Avatar asked Feb 06 '23 14:02

TechCrunch


2 Answers

You can use in JPA enumerated type. Have a look in the link below. http://tomee.apache.org/examples-trunk/jpa-enumerated/README.html

public enum State {
    STATE1,STATE2(STATE1),STATE3(STATE1,STATE2);

    private State[] previousStates;

    private State(){

    }
    private State(State ...state) {
        this.previousStates =state;
    }

    public State transition(State state) throws Exception {
        for(State tmp: state.previousStates) {
            if (this == tmp) {
                return state;
            }
        }
        throw new Exception("Illegal state");

    }

}

By implementing the method transition within the Enum you will be able to easily set new values for the enum in the JPA you can hide this invocation right into your set method and also it will just throw Exception if the status is incorrect.

like image 68
Alexander Petrov Avatar answered Feb 20 '23 08:02

Alexander Petrov


Alexander's proposal is fine as long as:

  • The complexity of state transitions can be managed in a single method
  • You don't want to add new states at runtime

For the first bullet point, you might want to consider to implement states as Objects not as enums. Each object/state could have a method that tells you if it was ok to switch to it depending on the current state.

interface State {
  boolean isSwitchOk(State currentState);
}

class FinishedState implements State {
   boolean isSwitchOk(State currentState) {
      ...
   }
} 

You could do it the other way round, as well, i.e. nextState instead of previousState.

In case you need states that can be added at runtime, you could persist them in the DB of your choice. For instance, map the following to your DB (as a JPA example)

@Entity
public class State {

   @OneToMany
   private List<State> permittedNextStates;

      public isSwitchOk(State nextState) {
        return permittedNextStates.contains(nextState);
      }
    }
 }

In your entity, you could then do

public class MyEntity {

   private State currentState;

   public void switchTo(State nextState) {
      if (currentState.isSwitchOk(nextState)) {
         this.currentState = state;
      }
   }
}
like image 43
Jan B. Avatar answered Feb 20 '23 07:02

Jan B.