-1

Given this:

 public enum States implements StateEnum {
    SHOWING_WELCOME,
    WAITING_FOR_PIN,
    CHECKING_PIN,
    RETURNING_CARD,
    SHOWING_MAIN_MENU,
    SHOWING_PIN_INVALID,
    SHOWING_CARD_LOCKED,
    SHOWING_BALANCE,
    SHOWING_WITHDRAW_MENU,
    SHOWING_TAKE_CASH,
    TERMINATED
}

public enum Events implements EventEnum {
    cardPresent,
    cardExtracted,
    pinProvided,
    pinValid,
    pinInvalid,
    tryAgain,
    noMoreTries,
    cancel,
    confirm,
    menuShowBalance,
    menuWithdrawCash,
    menuExit,
    switchOff,
    cashExtracted
}

I would like to know if there is a way to create an algorithm to automatize this:

from(SHOWING_WELCOME).transit(
    on(cardPresent).to(WAITING_FOR_PIN).transit(
        on(pinProvided).to(CHECKING_PIN).transit(
            on(pinValid).to(SHOWING_MAIN_MENU).transit(
                on(menuShowBalance).to(SHOWING_BALANCE).transit(
                    on(cancel).to(SHOWING_MAIN_MENU)
                ),
                on(menuWithdrawCash).to(SHOWING_WITHDRAW_MENU).transit(
                    on(cancel).to(SHOWING_MAIN_MENU),
                    on(confirm).to(SHOWING_TAKE_CASH).transit(
                        on(cashExtracted).to(SHOWING_MAIN_MENU)
                    )
                ),
                on(menuExit).to(RETURNING_CARD)
            ),
            on(pinInvalid).to(SHOWING_PIN_INVALID).transit(
                on(tryAgain).to(WAITING_FOR_PIN),
                on(noMoreTries).to(SHOWING_CARD_LOCKED).transit(
                    on(confirm).to(SHOWING_WELCOME)
                ),
                on(cancel).to(RETURNING_CARD)
            )
        ),
        on(cancel).to(RETURNING_CARD).transit(
            on(cardExtracted).to(SHOWING_WELCOME)
        )
    ),
    on(switchOff).finish(TERMINATED)
);

I was thinking to create two list (Events and States) to use the values in this way:

on(Events.valueOf(EventsList.get(0))).to(States.valueOf(EventsList.get(0)).trans it(

...

But, Im not sure which is the pattern for iterating.

I really appreciate any advise.

Thank you

//////////////////////////// UPDATED///////////////////////////////////

Solution based on the @Dukeling advice

  public  Map<States, List<Events>> transitMap;
   public Map<Events, States> toMap;

void transitCaller(States initialState, Events events)
  {
  transitCallerHelper(on(events).to(initialState),       
  transitMap.get(initialState));
  }

Transition  transitCallerHelper(Transition toResult, List<Events> events)
 {
   List<Transition> transitCalls = new ArrayList<Transition>();
   for (Events e: events)
    {
      States s = toMap.get(e);
      if (isFinishEvent(e)) // or isFinishState(s)
      transitCalls.add(on(e).finish(s));
   else
    {
      events = (s != null ? transitMap.get(s) : null);
      if (events == null)
         transitCalls.add(on(e).to(s));
     else
         transitCalls.add(transitCallerHelper(on(e).to(s), events));
    }
  }
 return toResult.transit(transitCalls.get(0));

}

user1069571
  • 17
  • 3
  • 8

1 Answers1

0

My initial thought would be to have maps to define your transit and to mappings:

Map<States, List<Events>> transitMap;
Map<Events, States> toMap;

You can store these mappings in a text file somewhere from which you can construct the above maps.

From here you can create a recursive method which calls your methods:
(It's a bit messy since from returns a different type)

void transitCaller(State initialState)
{
   from(initialState).transit(getTransitArgs(transitMap.get(ini‌​tialState)));
}

Transition transitCallerHelper(Transition toResult, List<Events> events)
{
   return toResult.transit(getTransitArgs(events));
}

Transition[] getTransitArgs(List<Events> events)
{
   List<Transition> transitArgs = new ArrayList<Transition>();
   for (Events e: events)
   {
      States s = toMap.get(e);
      if (isFinishEvent(e)) // or isFinishState(s)
         transitArgs.add(on(e).finish(s));
      else
      {
         List<Events> events = (s != null ? transitMap.get(s) : null);
         if (events == null)
            transitArgs.add(on(e).to(s));
         else
            transitArgs.add(transitCallerHelper(on(e).to(s), events));
      }
   }
   return transitArgs.toArray(new Transaction[0]);
}

(Add error checking as appropriate)


Side note: You may want to make States and Events singular as opposed to plural, since each value in the enum only defines a single state and event respectively.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • thanks for your valuable answer, sorry I have a question: "from" has a different type of "on" and finish, both of them are "Transaction", since we need to use the recursive method, it should failed no?. Im trying to apply for this code: https://pastebin.com/fewi8R0F (demo) for this libray: https://github.com/Beh01der/EasyFlow. Thanks. I made a modification, but it does not works, please see the modified/extended question. – user1069571 Mar 29 '17 at 13:26
  • @user1069571 But it also has a `transit` method? In that case you may want to put that method in an `interface`, which you implement in both classes. You can then use this interface in place of `ReturnType` in the recursive method, since having a `transit` method is the only thing the recursive method cares about. Or you can move the bulk of the `transitCallerHelper` method as is to another method (`getTransitArgs`) which returns `List`, and then do `from(initialState).transit(getTransitArgs(transitMap.get(initialState)));` in `transitCaller`. – Bernhard Barker Mar 29 '17 at 13:37
  • `toResult.transit(transitCalls.get(0));` won't work - that always calls `transit` with only a single item from our list (`get(0)` gets the first element). Just use `transitCalls.toArray(new Transaction[0])` instead to convert that to an array, which should be fine. – Bernhard Barker Mar 29 '17 at 13:52
  • Im sorry, two things : 1. : doing it: from(initialState).transit(getTransitArgs(transitMap.get(ini‌​tialState))), it returns a list of Events, but getTransitArgs(States initialState) requires as you know States. 2. Sorry Im not clear about getTransitArgs function it will returns List ? Thanks , many thanks – user1069571 Mar 29 '17 at 14:38
  • 1. I'm not sure what you're referring to. I don't see a problem with the code - we have access to all the information we need. 2. Since `transit` takes an array as parameter (not a `List`), it's simpler to return `Transition[]`. The `toArray` function returns an array. – Bernhard Barker Mar 29 '17 at 16:09