Foto av Johan Eltes

TSSS 2007 Ramverket RIFE

// Johan Eltes

RIFE är lite av en udda fågel bland web-ramverken. I någon mening skulle man kunna kalla det för Java-världens Rails (men utan Ruby). Det är framför allt ett par företeelser som gör det speciellt:

  • Meta-data drivna dialoger för CRUD-operationer
  • Separation av regler från modell-klasser, men fortfarande i Java-form
  • Web-navigering bygger på “continuations”, som via bytekodsmanipulation görs tillgänglig direkt i Java

Liknelsen vid Rails syftar i första hand på metadata-drivna CRUDs. Mer intressant är kanske stödet för regler och “continuations”.

Regler

Regler (“Conditions”) är klass som definierar regler för fälts längder, tillåtna värden, valideringsregler tvärs fält etc, som gäller en annan klass (modell-POJO). Här kommer ett exempel med en NewsItem modell-POJO och motsvarande regel-klass:

public class NewsItem {
  private Integer id;
  private String title;
  private String text;
  private byte[] image;
  public void setId(Integer id) { this.id = id; }
  public Integer getId() { return id; }
  public void setTitle(String title) { this.title = title; }
  public String getTitle() { return title; }
  public void setText(String text) { this.text = text; }
  public String getText() { return text; }
  public void setImage(byte[] image) { this.image = image; }
  public byte[] getImage() { return image; }
}
public class NewsItemMetaData extends MetaData {
  public void activateMetaData() {
    addConstraint(new ConstrainedProperty("title")
      .notNull(true)
      .maxLength(90));
    addConstraint(new ConstrainedProperty("text")
      .mimeType(MimeType.APPLICATION_XHTML)
      .autoRetrieved(true)
      .fragment(true)
      .notNull(true)
      .notEmpty(true));
    addConstraint(new ConstrainedProperty("image")
      .mimeType(MimeType.IMAGE_PNG)
      .contentAttribute("width", 120)
  }
}

Regel-klassen vävs samman (av en klass-laddare) så att man kan casta POJO:n för att göra en validering. Observer att valideringen (och reglerna) är oberoende av lager och sammanhang (web, service-layer, container, unittest etc)

Continuations

Continuations är ett avancerat stöd som på ett bräde löser de stora frågorna med web-baserad navigering. Utan en enda rad web-relaterad kodning, blir hela applikationen fullständigt robust vad gäller back-knapp, nya browser-fönster etc. Men inte genom att slå av möjligheten, utan genom att göra så det det fungerar som användaren förväntar sig. Se tidigare blog om continuations.

Continuations kräver att man har state på servern (egentligen en del av call-stacken). För att undvika skalbarhetsproblem, har RIFE integrerat Open Terracotta. Terracotta stödjer minnesbaserad replikering på JVM-nivå.

Continuation-stödet har beskrivits separat och lämnats in som en JCP JSR.

RIFE-teamet är en frisk fläkt som jobbar under mottot “What needs to be done, needs to be done”! Avslutningsvis ett exempel. Nedanstående kod är 100% av koden (förutom vy-definitionerna) för ett gissa-tal-spel. Tänk er ett use-case:

  1. Slumpa fram ett tal mellan 0 och 100
  2. Visa dialogen
  3. Tills användaren gissat rätt:
    1. Användaren matar in ett värde
    2. Validera att värdet är mellan 0 och 100. Om fel, meddela användaren och fortsätt vid 2.
    3. Om ej rätt gissning, visa om talet var större eller mindre än svaret.
    4. Visa dialogen och fortsätt vid 2.
  4. Visa svaret och antal gissningar.

Här kommer koden (ledtrådar: print() -> visa dialog, pause() -> Vänta på submit):

public class Game extends Element {
  private static Random randomNumbers = new Random();
  public void processElement() {

    Template template = getHtmlTemplate("game");
    int answer = 0, guesses = 0, guess = -1;

    answer = randomNumbers.nextInt(101);
    while (guess != answer) {
      print(template);
      pause();
      template.clear();
      guess = getParameterInt("guess", -1);
      if (guess < 0 || guess > 100) {
        template.setBlock("warning", "invalid");
        continue;
      }
      guesses++;

      if (answer < guess) template.setBlock("msg", "lower");
      else if (answer > guess) template.setBlock("msg", "higher");
    }

    ContinuationContext.getActiveContext().removeContextTree();

    template = getHtmlTemplate("success");
    template.setValue("answer", answer);
    template.setValue("guesses", guesses);
    print(template);
  }
}

Är detta en ny uppfinning?

Visa ovanstående för vilken stor-dator-utvecklare som helst (ev. pensionerad), som har skrivit transaktionssystem i ISPF/TSO + Cobol. Continuations fanns i OS 390 1987.

Kommentarer