Cameleon OSP im Vergleich mit Webmacro und Velocity im Javamagazin 03.02

Textauszug aus dem Heft 03.02 des Javamagazins. Im Titelthema erfolgt die Vorstellung von Cameleon OSP im Anschluss an Webmacro und Velocity wie folgt:
. . .
 
Cameleon - die Alternative

Im letzten Abschnitt dieses Beitrags werfen wir nun einen Blick auf das Web-Framework Cameleon [5]  www.must.de/cameleon.html. Viele Leser, denen Cameleon noch nicht bekannt ist, werden sicherlich einwenden, warum ein weiteres Framework betrachtet werden muss, wenn bereits ausreichend bekannte und gute Alternativen bestehen. Der Ansatz, der von Cameleon verfolgt wird, ist durchaus als außergewöhnlich zu betrachten: Es ist vorgesehen, Applikationenen mittels Swing, Servlets oder JSP auf der Grundalge von Data-Objects zu bilden. Hierbei wird besonders Wert darauf gelegt, Datenbank-Applikationen weitgehend zu unterstützen.

Der besondere Vorteil liegt bei Cameleon darin, dass auf der Grundlage von Datenbanken, die durch Data-Objects abgebildet werden, die Applikation als Swing-Anwendung, JSP oder Servlet aufgebaut werden kann. Somit besitzen verschiedene Darstellungen die gleiche Datengrundlage.
 
 
DataStructures

Data Structures bilden unter Cameleon die Grundlage für Applikationen, egal welchen Typs. Durch Data Structures (Data Objects) werden Datenbank-Tabellen durch eine Klasse abgebildet und können somit einfach bearbeitet werden. In Listing 1 sehen Sie die Datenstruktur der Cameleon-Beispielapplikation Cooblook. Auf der Grundlage einer solchen Datenstruktur können nun User-Interfaces mit Hilfe von Swing, JSP oder Servlets gestaltet werden. Weitere Informationen hierzu sind den beiliegenden Hilfe Dokumenten zu finden.
 
Listing 1
//elementary!

/*
 * Public Domain Sample Code 
 */

package de.jugs.cookbook;

import de.must.dataobj.*;
import java.util.GregorianCalendar;

/**
 * @author Christoph Mueller
 */
public final class DoCookbook extends DataObject {

  public static final String tableName = "Cookbook";

  public static final AbstractAttribute cookNI = new NumericAttribute("Rezeptnummer intern", "RezeptNI");
  public static final AbstractAttribute title = new VarcharAttribute("Rezept-Bezeichnung", "RezeptBez", 80);
  public static final AbstractAttribute parts = new VarcharAttribute("Zutaten", "Zutaten", 2000);
  public static final AbstractAttribute preparation = new VarcharAttribute("Zubereitung", "Zubereit", 4000);

  public static final AbstractAttribute[] attributes = {
    cookNI,
    title,
    parts,
    preparation,
    new NumericAttribute("Portionen", "Portionen"),
    new NumericAttribute("Brennwert pro Portion", "Brennwert"),
    new NumericAttribute("Garzeit", "Garzeit"),
    new VarcharAttribute("Quelle", "Quelle", 254),
    new VarcharAttribute("Bereitgestellt von", "Von", 60),
    new DateAttribute("Bereitgestellt am (Datum)", "Vom"),
    new NumericAttribute("Rezepttyp", "Typ"),
    new BooleanAttribute("Für Diabetiker geeignet", "Diabetiker"),
  };

  public static final Index[] indices = {
    new Index (
      new IndexItem[] {
        new IndexItem("RezeptNI", IndexItem.ASCENDING),
      },
      Index.UNIQUE
    ),
  };

  public DoCookbook(DataObjectConstructionDetails dataObjectConstructionDetails) {
    super(dataObjectConstructionDetails);
  }

  public String getTableName() {
    return tableName;
  }

  public AbstractAttribute[] getAttributes() {
    return attributes;
  }

  public Index[] getIndices() {
    return indices;
  }

}


 
Servlet

Um den Vorgang der Servlet-Programmierung mit Cameleon noch etwas genauer zu erläutern, werden wir in diesem Abschnitt die grundlegenden Schritte anhand des beiliegenden Cookbook-Beispiels nachvollziehen.

Die gesamte Applikation basiert auf einem zentralen Servlet, zu finden unter dem Package de.jugs.cookbook.Main. Die Servlet-Klasse muss jeweils von de.must.markup.MainStd abgeleitet werden. Das Servlet ist zunächst dafür verantwortlich, dass Zugriff auf globale Eigenschaften gewährt wird und eine Session angelegt wird. Listing 2 zeigt die betreffende Klasse am Beispiel der Cookbook-Applikation:
 
Listing 2
//elementary!

/*
 * Public Domain Sample Code 
 */

package de.jugs.cookbook;

import de.must.middle.GlobalStd;
import de.must.markup.*;

/**
 * @author Christoph Mueller
 */
 public final class Main extends MainStd {

  public Main() {
  }

  protected GlobalStd getGlobal() {
    return Global.getInstance();
  }

  protected GlobalStd getGlobal() {
    return Global.getInstance();
  }

  protected Class getSessionClass() {
    return Session.class;
  }

}

Alle speziellen Einstellungen werden anschließend in einem getrennten Session-Objekt hinterlegt. Hierzu wird eine Klasse von de.must.markup.SesssionStd abgeleitet Die Servet-Implementierung des Cookbbok-Beispiels ist unter de.jugs.cookbook.Session abgelegt.

Das dritte wichtige Element im Framework ist die Container-Klasse, welche Input/Output-Felder an Datenbanktabellen anbindet. Die Container-Klasse des Cookbook-Beispiels ist mit dem Namen Cookbook Administration bezeichnet und wird von DataPropertyAdministration abgeleitet. Wie zu erwarten, befindet sich die Implementierung der Beispielklasse unter dem Package de.jugs.cookbook.CookbookAdministration Hier ein kleiner Ausschnitt der Klasse zur Initialisierung eines Text-Fields:

createTextField(sessionData.getResourceString
                    ("TEXT_RECIPE_TITLE"), "RezeptBez");

Zugriff auf das entsprechende Session-Objekt wird durch Übergabe an den Konstruktor der Klasse realisiert:

public CookbookAdministration(SessionData sessionData)
{
...
}

Um die verschiedenen Bestandteile der Applikation nun in ein Gesamtschema einzureihen werfen Sie einen Blick auf Abbildung 5:

Die Übersicht verdeutlicht noch einmal anschaulich, welche Beziehungen zwischen den einzelnen Komponenten bestehen. Das Servlet „Main“ ist der einzige Bestandteil der Applikation, auf den ein Benutzer später von „außen“ zugreifen kann. Die wichtigste Verwaltungsarbeit übernimmt das Session-Objekt. Hier werden zentrale Einstellungen für den Layouter hinterlegt. Um die Darstellung / Präsentation vorzunehmen, werden Objekte innerhalb eines Containers gesammelt (Frame-like Container). Zur Verfügung stehen hierbei die Objekte TextField, TextArea und ComboBox. Die HTML-Ausgabe wird anschließend automatisch vom Layouter generiert (de.must.markup.HostLayout).
 
Listing 3
//elementary!

/*
 * Public Domain Sample Code 
 */

package de.jugs.cookbook;

import de.must.markup.*;
import de.must.middle.GlobalStd;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

/**
 * Session class. Assigned by class Main. This is a place to define the look
 * and feel for the sessions in general. For example, different sessions may
 * user different layouts.
 * @author Christoph Mueller
 */
public final class Session extends SessionStd {

  private Layout layout;

  public Session() {
    super(Constants.ACTION_FOR_POST, Constants.BASIC_TITLE);
  }

  protected void build(SessionData sessionData) {
    if (sessionData.locale.getLanguage().equals(java.util.Locale.GERMAN.getLanguage())) {
      sessionData.setResourceBundle(new de.jugs.cookbook.Res_de_DE());
    } else {
      sessionData.setResourceBundle(new de.jugs.cookbook.Res());
    }
    sessionData.imageDirectory = Constants.IMAGE_DIRECTORY;
    sessionData.entitlement = new Entitlement(sessionData);
    sessionData.menuBar = new MainMenu(sessionData);
    sessionData.toolBar = new ToolBar(sessionData);
    sessionData.layout = new HostLayout();
    sessionData.layout.setFooterTagSequence(Constants.FOOTER);
    baseInvoke(sessionData.menuBar);
  }

  protected GlobalStd getGlobal() {
    return Global.getInstance();
  }

}

. . .

Autor des Artikels: Sebastian Eschweiler