Mentawai Web Framework

Sticky Actions

Sticky Actions é a solução do Mentawai para a persistência de estado ao longo de várias requisições diferentes de um mesmo usuário.

Pegue o exemplo clássico do jogo Acerte o Número onde você tenta adivinhar um número de 0 a 100 enquanto o computador lhe diz se o seu chute foi maior ou menor do que a resposta. (Ex: http://rifers.org/03_numberguess)

Há várias informações de estado que precisam ser mantidas:

  • A resposta secreta

  • Quantos chutes eu já dei até o momento

  • Há quanto tempo eu estou tentando acertar

A solução padrão para esse problema é colocar tudo na sessão do usuário (HttpSession), mas o Mentawai oferece uma abordagem mais natural: Sticky Actions

Sticky Action irão persistir o seu estado durante várias requisições, a partir do momento que você chamar a função adhere() até o momento que você chamar disjoin() para liberar a instância da action, ou seja, a mesma instância da action vai ser utilizada para várias requisições consecutivas.

Você pode também implementar a função onRemoved() para aqueles casos onde a sessão expira ou é invalidada antes do método disjoin() ser chamado. (Por exemplo quando o usuário deixa o site, fecha o browser, ou dá um logout).

Abaixo temos um exemmplo de como implementar o jogo Acerte o Número usando apenas a sessão. Depois veremos um exemplo de como fazer a mesma coisa usando uma sticky action.

  public class NumberGuess extends BaseAction implements Validatable {
      
      public static final String BINGO = "bingo";
      public static final String FIRST = "first";
      public static final String WRONG = "wrong";    
      
      private static final Random random = new Random();
      
      private void incrementGuesses() {
          
          Integer i = (Integer) session.getAttribute("guesses");
          
          session.setAttribute("guesses", new Integer(i.intValue() + 1));
          
      }
      
      public void initValidator(Validator val, String innerAction) {
              
              val.add("guess", new IntegerRule(0, 100), "Invalid guess!");
              
      }
      
      public String execute() throws Exception {
          
          // Check if a game is in progess, by fetching the current answer...
          
          int answer = -1;
          
          if (session.getAttribute("answer") == null) {
              
              answer = random.nextInt(101);
                
              session.setAttribute("answer", new Integer(answer));
              
              session.setAttribute("guesses", new Integer(0));
              
          } else {
              
              answer = ( (Integer) session.getAttribute("answer")).intValue();
              
          }
          
          if (input.getValue("guess") != null) {
              
              incrementGuesses();
              
              int guess = input.getIntValue("guess");
              
              if (answer == guess) {
                  
                  output.setValue("answer", session.getAttribute("answer").toString());
                  
                  output.setValue("guesses", session.getAttribute("guesses").toString());
                  
                  session.removeAttribute("answer");
                  
                  session.removeAttribute("guesses");
                  
                  return BINGO;
                  
              } else {
                  
                  if (guess < answer) {
                      
                      addMessage("Number is higher!"); // of course this can be i18n...
                      
                  } else {
                      
                      addMessage("Number is lower!"); // of course this can be i18n...
                      
                  }
                  
                  return WRONG;
              }
          }
          
          return FIRST;
      }
  }
	

Now welcome to sticky actions:

  public class NumberGuessSticky extends BaseAction implements Validatable {
      
      public static final String BINGO = "bingo";
      public static final String FIRST = "first";
      public static final String WRONG = "wrong";    
      
      // because this action is sticky, you can keep your values here across requests...
      private int answer = -1;
      private int guesses = 0;
      
      private static final Random random = new Random();
      
      public void initValidator(Validator val, String innerAction) {
              
              val.add("guess", new IntegerRule(0, 100), "Invalid guess!");
              
      }
      
      public String execute() throws Exception {
          
          System.out.println("Executing action: " + this.toString());
          
          // Check if a game is in progess, by fetching the current answer...
          
          if (answer == -1) {
              
              answer = random.nextInt(101);
              
              guesses = 0;
              
              adhere();
              
          }
          
          if (input.getValue("guess") != null) {
              
              guesses++;
              
              output.setValue("guesses", String.valueOf(guesses));
              
              int guess = input.getIntValue("guess");
              
              if (answer == guess) {
                  
                  output.setValue("answer", String.valueOf(answer));
                  
                  disjoin();
                  
                  return BINGO;
                  
              } else {
                  
                  if (guess < answer) {
                      
                      addMessage("Number is higher!"); // of course this can be i18n...
                      
                  } else {
                      
                      addMessage("Number is lower!"); // of course this can be i18n...
                      
                  }
                  
                  return WRONG;
              }
          }
          
          return FIRST;
      }
  }