Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Struts] dynamische Formulare

24 views
Skip to first unread message

Michael Ernst

unread,
Aug 27, 2005, 9:47:31 AM8/27/05
to
Ich bin auf der Suche nach einer Möglichkeit dynamisch Formulare zu
erzeugen. Im speziellen möchte ich für eine sprachunabhängige Anwendung so
viele Textfelder anzeigen wie Sprachen installiert sind und diese später
dann natürlich auch in der Action verarbeiten. Was bietet Struts für solche
Fälle? Google hat leider nicht geholfen!

MfG Michael


Timo Stamm

unread,
Aug 27, 2005, 9:54:22 AM8/27/05
to
Michael Ernst wrote:
> Ich bin auf der Suche nach einer Möglichkeit dynamisch Formulare zu
> erzeugen. Im speziellen möchte ich für eine sprachunabhängige Anwendung so
> viele Textfelder anzeigen wie Sprachen installiert sind und diese später
> dann natürlich auch in der Action verarbeiten. Was bietet Struts für solche
> Fälle?

Mit Struts kommst du da nicht weiter.


Timo

Michael Ernst

unread,
Aug 27, 2005, 10:15:21 AM8/27/05
to
Und was ist dann die ultimative Lösung oder Lösungsansatz für dieses
Problem?
Womit macht man so etwas? Ich denke ich bin nicht der einzige der so etwas
machen möchte oder schon getan hat.

MfG Michael


Timo Stamm

unread,
Aug 27, 2005, 10:44:08 AM8/27/05
to
Michael Ernst wrote:
> Womit macht man so etwas?

"Von Hand" mit Servlet und JSP zum Beispiel.

Bei Struts gibt es die DynaActionForms, aber soweit ich diese verstanden
habe ist es auch damit nicht möglich, zur Laufzeit Formulare zu generieren.

Mit JSF ist es mit Sicherheit möglich, ich vermute aber mal dass der
Aufwand astronomisch ist weil man sich erst in das nicht gerade schlanke
Framework einarbeiten muss.

Tapestry ist darauf SWIW auch nicht ausgelegt.

Auch Wicket hat meines Wissens nichts dafür an Bord. Die normalen
Formulare werden durch Beans (= statisch) definiert. Immerhin sehe ich
Wicket als den besten Kandidaten, es in der Richtung zu erweitern.


> Ich denke ich bin nicht der einzige der so etwas machen möchte oder schon getan hat.

Du bist auf jeden Fall nicht der einzige der eine einfache Möglichkeit
dafür in den gängigen Frameworks vermisst hat.

Die Tatsache, dass es dazu im Netz keine Tutorials gibt spricht dafür,
dass niemand eine wirklich elegante Lösung mit den üblichen Verdächtigen
umgesetzt hat.


Timo

Marian Aldenhövel

unread,
Aug 27, 2005, 10:51:25 AM8/27/05
to
Hallo,

> Im speziellen möchte ich für eine sprachunabhängige Anwendung so
> viele Textfelder anzeigen wie Sprachen installiert sind und diese später
> dann natürlich auch in der Action verarbeiten. Was bietet Struts für solche
> Fälle?

Du kannst Eigenschaften in Form-Klassen per Index oder als Map assoziativ
"vervielfachen". In den JSP-Views kannst Du dann zum Beispiel logic:iterate
verwenden um HTML-Eingabeelemente für alle diese Eigenschaften auszugeben.

Ciao, MM
--
Marian Aldenhövel, Rosenhain 23, 53123 Bonn. +49 228 624013.
http://www.marian-aldenhoevel.de
"Sollte ein Verstoß gegen das Grundgesetz festgestellt werden, heißt es dann
aber nur für alle Parteien, daß das Grundgesetz gemäß dem Urteil ergänzt
werden muss. Nach einer Ergänzung wird dann das Luftsicherheitsgesetz neu
beschlossen" - Prof. Dr. Peter Paul Gantzer

Michael Ernst

unread,
Aug 28, 2005, 5:40:24 PM8/28/05
to
Ok, funktioniert!
Danke

MfG Michael


Timo Stamm

unread,
Aug 28, 2005, 6:40:41 PM8/28/05
to
Michael Ernst wrote:
> Ok, funktioniert!
> Danke


Sorry, da hab ich Struts zu früh aufgegeben :)

Malte Schneider

unread,
Aug 29, 2005, 3:13:47 AM8/29/05
to

Aber auch mit dem Ansatz ist nicht alles zu erschlagen, irgendwie kommt
man auch mit Struts nicht weiter.

Malte

Stefan Matthias Aust

unread,
Aug 29, 2005, 4:05:07 AM8/29/05
to
Timo Stamm schrieb:

> Auch Wicket hat meines Wissens nichts dafür an Bord. Die normalen
> Formulare werden durch Beans (= statisch) definiert. Immerhin sehe ich
> Wicket als den besten Kandidaten, es in der Richtung zu erweitern.

Ich glaube, dass geht mit Wicket nicht. Wicket braucht zwingend für
jede in der Page-Klasse definierten Komponente eine passende wicket:id
im HTML. Das verhindert so weit ich sehe leider jede Form der Dynamik.
Das hat mir zur Zeit das Rahmenwerk etwas verleitet.

--
Stefan Matthias Aust // Lassen Sie uns durch, wir sind Arzt!

Timo Stamm

unread,
Aug 29, 2005, 8:32:14 AM8/29/05
to
Stefan Matthias Aust wrote:
> Timo Stamm schrieb:
>
>> Auch Wicket hat meines Wissens nichts dafür an Bord. Die normalen
>> Formulare werden durch Beans (= statisch) definiert. Immerhin sehe ich
>> Wicket als den besten Kandidaten, es in der Richtung zu erweitern.
>
>
> Ich glaube, dass geht mit Wicket nicht. Wicket braucht zwingend für
> jede in der Page-Klasse definierten Komponente eine passende wicket:id
> im HTML. Das verhindert so weit ich sehe leider jede Form der Dynamik.
> Das hat mir zur Zeit das Rahmenwerk etwas verleitet.


Wozu schreibt man denn ein komponentenbasiertes System wenn man sich die
Flexibilität wieder nimmt indem alle Komponenten in der Template
definiert werden müssen?

Ich habe vor, demnächst ein Projekt mit Wicket umzusetzen, bei dem
"dynamische Formulare" die wichtigste Anforderung ist. Wenn das mit
Wicket nicht geht, müsste ich jedes Formular zwei mal definieren,
nämlich im Model und im View (Horror).

Bisher habe ich mir nur die Beispiele angeschaut und im Source
rumgestöbert. Bei dem forminput-example zum Beispiel sind die
Fehlermeldungen _nicht_ in der Template angegeben. Grundsätzlich ist es
also möglich, Komponenten zu rendern die nicht im HTML der Page Klasse
referenziert sind.

Mir ist auch aufgefallen dass manche Komponenten ihr eigenes HTML
mitbringen. Vielleicht war es ein bisschen naiv von mir, davon
auszugehen dass man problemlos mit sub-templates arbeiten kann, die ihre
eigene Template in die Page setzen.


Hast du Wicket mal eingesetzt? Mich würde sehr interessieren, ob du den
Aufwand, mit Wicket komplett dynamische Formulare zu machen, für so
gross hälst dass du eher traditionell jedes Formular einzeln definierst.


Ich habe ein eigenes komponentenbasiertes System als alternative. Das
ist viel kleiner als Wicket (Component.java bei Wicket: ~2000 Zeilen;
Component.java bei mir: ~100 Zeilen) und deshalb viel flexibler
(dynamische Formulare wären kein Problem), aber auf der anderen Seite
fehlen viele Details, es gibt noch keinen einheitlichen Umgang mit dem
Model und vor allem: es ist noch sehr frisch, und noch nicht erprobt.


Ich muss mich sehr bald entscheiden ob ich für das Projekt etwas
erprobtes einsetze (Wicket) oder das eigene Framework benutze. Deshalb
wären Meinungen zu Wicket (insb. dynamische Formulare) für mich sehr
hilfreich und ich würde mich über jedes Feedback freuen.

Timo

Stefan Matthias Aust

unread,
Aug 29, 2005, 9:09:41 AM8/29/05
to
Timo Stamm schrieb:

> Wozu schreibt man denn ein komponentenbasiertes System wenn man sich die
> Flexibilität wieder nimmt indem alle Komponenten in der Template
> definiert werden müssen?

Nun, das macht es möglich, WYSIWYG-Editoren für das Erstellen der Seiten
zu benutzen. Wicket ist zwar ein Komponenten-basiertes System, nicht
jedoch Komponenten-orientiert (wie etwa SeaSide) sondern immer noch
seitenorientiert.

Vielleicht übersehe ich aber auch nur etwas.

Denn das Bean-Editor-Beispiel müsste eigentlich zeigen, wie man
dynamisch Formulare baut. Vielleicht ist der Trick einfach, ein

<div wicket:id="whatever>...</div>

zu benutzen, und dann dort das komplette Formular selbst zu generieren.

> Bisher habe ich mir nur die Beispiele angeschaut und im Source
> rumgestöbert. Bei dem forminput-example zum Beispiel sind die
> Fehlermeldungen _nicht_ in der Template angegeben.

Die Fehlermeldungen stammen aus zugehörigen properties-Dateien. Wenn du
ein Eingabefeld mit der ID "xyz" hast, dem du ein RequiredValidator
zuweist, dann muss in der Properties-Datei ein

form-abc.xyz.RequiredValidator=Ey du, hier fehlt ein Wert!

stehen. Derartige Fehlermeldungen werden dann (leider in beliebiger
Reihenfolge, weil da eine HashMap benutzt wird) in einem FeedbackPanel
als Liste angezeigt.

Fehlermeldungen direkt an Eingabefelder zu schreiben oder Labels zu
Eingabefeldern mit Fehlern oder die Eingabefelder selbst hervorzuheben -
das waren Dinge, die ich nicht generisch hinbekommen habe, eben weil ich
das vorhandene HTML nicht ändern konnte. Einzig sowas ging:

<span wicket:id="xyz-indicator><input wicket:id="xyz" .../></span>

und dann kann man eine eigene Komponente an xyz-indicator binden, die
dann ein bisschen HTML erzeugt, mit Hilfe dessen das Label (über die
Komponente definiert) umgefärbt und das Eingabefeld z.B. umrandet werden
kann.

> Hast du Wicket mal eingesetzt?

Ja.

> Mich würde sehr interessieren, ob du den
> Aufwand, mit Wicket komplett dynamische Formulare zu machen, für so
> gross hälst dass du eher traditionell jedes Formular einzeln definierst.

Nein, habe ich nicht geschafft, aber mir ist eben eingefallen, dass man
man das BeanEditor-Beispiel studieren muss.

> Ich habe ein eigenes komponentenbasiertes System als alternative. Das
> ist viel kleiner als Wicket (Component.java bei Wicket: ~2000 Zeilen;
> Component.java bei mir: ~100 Zeilen)

Erzähle bitte mehr darüber.

Timo Stamm

unread,
Aug 29, 2005, 11:48:36 AM8/29/05
to
Stefan Matthias Aust wrote:
> Timo Stamm schrieb:
>
>> Wozu schreibt man denn ein komponentenbasiertes System wenn man sich
>> die Flexibilität wieder nimmt indem alle Komponenten in der Template
>> definiert werden müssen?
>
>
> Nun, das macht es möglich, WYSIWYG-Editoren für das Erstellen der Seiten
> zu benutzen.

Schon klar, mich stört aber das "müssen". "können" fände ich besser.


> Wicket ist zwar ein Komponenten-basiertes System, nicht
> jedoch Komponenten-orientiert (wie etwa SeaSide) sondern immer noch
> seitenorientiert.

Das ist wohl der Knackpunkt. Smalltalk kommt aber nicht in Frage.

> Vielleicht übersehe ich aber auch nur etwas.
>
> Denn das Bean-Editor-Beispiel müsste eigentlich zeigen, wie man
> dynamisch Formulare baut. Vielleicht ist der Trick einfach, ein
>
> <div wicket:id="whatever>...</div>
>
> zu benutzen, und dann dort das komplette Formular selbst zu generieren.

Ich würde ungern an Wicket vorbei programmieren. Es wäre gut, wenn man
die bestehenden Formular-Komponenten von Wicket dafür benutzen kann.
Wenn man dafür den Wicket source patchen muss oder tief in die Interna
greift ist das keine Option, das ist auf lange Sicht mehr Arbeit.


>> Bisher habe ich mir nur die Beispiele angeschaut und im Source
>> rumgestöbert. Bei dem forminput-example zum Beispiel sind die
>> Fehlermeldungen _nicht_ in der Template angegeben.
>
>
> Die Fehlermeldungen stammen aus zugehörigen properties-Dateien. Wenn du
> ein Eingabefeld mit der ID "xyz" hast, dem du ein RequiredValidator
> zuweist, dann muss in der Properties-Datei ein
>
> form-abc.xyz.RequiredValidator=Ey du, hier fehlt ein Wert!
>
> stehen.

Der _Inhalt_ der Fehlermeldungen stammt aus properties Dateien. Die
Fehlermeldung wird aber von der Komponente FormComponentFeedbackBorder
gerendert, die auch eine eigene Template hat.

Deshalb meine Meinung, dass nicht zwangsweise jede gerenderte Komponente
in der Page Template auftauchen muss.

> Derartige Fehlermeldungen werden dann (leider in beliebiger
> Reihenfolge, weil da eine HashMap benutzt wird) in einem FeedbackPanel
> als Liste angezeigt.

Da kannte wohl jemand die LinkedHashMap nicht?

> Fehlermeldungen direkt an Eingabefelder zu schreiben oder Labels zu
> Eingabefeldern mit Fehlern oder die Eingabefelder selbst hervorzuheben -
> das waren Dinge, die ich nicht generisch hinbekommen habe, eben weil ich
> das vorhandene HTML nicht ändern konnte. Einzig sowas ging:
>
> <span wicket:id="xyz-indicator><input wicket:id="xyz" .../></span>
>
> und dann kann man eine eigene Komponente an xyz-indicator binden, die
> dann ein bisschen HTML erzeugt, mit Hilfe dessen das Label (über die
> Komponente definiert) umgefärbt und das Eingabefeld z.B. umrandet werden
> kann.

Hm. Das kling nicht gut.

>> Mich würde sehr interessieren, ob du den Aufwand, mit Wicket komplett
>> dynamische Formulare zu machen, für so gross hälst dass du eher
>> traditionell jedes Formular einzeln definierst.
>
>
> Nein, habe ich nicht geschafft, aber mir ist eben eingefallen, dass man
> man das BeanEditor-Beispiel studieren muss.


Ahh, das BeanEditor-Beispiel gab es in 1.0 noch nicht.

Leider wären Beans jedoch auch keine Lösung. Es gibt in dem Projekt für
das ich Wicket in Betracht ziehe keine Klassen, die das Datenmodel
repräsentieren. (Kurz gesagt, ich muss über Collections iterieren und
damit Komponenten mit Kindern versehen können.)

Selbst wenn, wären die Datentypen, die dieser Beaneditor in
Formularkomponenten umwandeln kann, längst nicht mächtig genug.


Ich werde mir mal anschauen was der Beaneditor alles macht, und ob es da
einen guten Ansatzpunkt gibt.

Das einfache Bean-Editor Beispiel mit einer handvoll Zeilen benutzt
übrigens das Paket wicket.extensions.markup.html.beanedit, dass 23(sic!)
Dateien enthält.

Dass man da so tief graben muss gefällt mir schon mal nicht.

>> Ich habe ein eigenes komponentenbasiertes System als alternative. Das
>> ist viel kleiner als Wicket (Component.java bei Wicket: ~2000 Zeilen;
>> Component.java bei mir: ~100 Zeilen)
>
>
> Erzähle bitte mehr darüber.


Puh, das ist eigentlich zu früh und auch nicht für die public domain
gedacht. Aber was darüber erzählen kann ich schon.

Es ist ein komplett komponentenorientierter Ansatz. Der Komponentenbaum
befindet sich in der Session.


Jede Komponente hat eine Methode "build", in der mit "set" Kinder
hinzugefügt werden können. Diese Methode wird oft vom User
implementiert, kann aber auch von komplexeren Komponenten implementiert
sein. Bei einer Listenkomponente sieht es vereinfacht so aus:

class List<T> extends Component {
private Collection<T> model;
// ...
public void build() {
for (T t : model) {
set(new String(i++), populate(t));
}
}
public abstract Component populate(T t);
// ...
}

Wicket macht ziemlich genau dasselbe, aber "build" findet im Konstruktor
statt. Der String der bei "set" übergeben wird ist übrigens der Name der
Komponente.


Wenn ein Request ankommt, wird er durch die Methode "beginRequest" durch
den Baum weitergeleitet. In jeder Komponente wird die Methode
"onRequest" aufgerufen, die von einer Komponente (zum Beispiel einem
Formularfeld) überschrieben werden kann.

Nachdem das rekursive "beginRequest" durchgelaufen ist, wird
"beginAction" gestartet. Auch hier wieder rekursiv, analog zu
"onRequest" wird "onAction" in jeder Komponente aufgerufen. Hier kann
zum Beispiel eine Button- oder Link-Komponente eine Methode aufrufen,
die der User implementieren kann. Die Trennung zu onRequest ist
sinnvoll, damit zum Beispiel alle Formularfelder das Model aktualisiert
haben bevor die Aktion ausgeführt wird.

Die Methode "render" wird mit einem PrintWriter als Argument aufgerufen,
und macht als default nichts anderes als in allen Kindern wieder
"render" aufzurufen.

In einer StringComponent sieht "render" dann so aus:

public final void render(PrintWriter out) {
out.print(str);
}


Als Template habe ich JSP und einfache Textdateien ausprobiert. Bisher
allerdings nur "flach", d.h. nur die direkten Kinder können in der
Template angesprochen werden. Es spricht aber nichts dagegen, auch
tiefer in den Komponentenbaum einzugreifen. Auch eine Template wie bei
Wicket wäre möglich, interessiert mich aber nicht weiter.

Eine Komponente wird in der Template übrigens über den Namen
identifiziert, der bei der Methode set(String name, Component child)
übergeben wird.

Diese Namen werden auch benutzt, um Formularfelder zu identifizieren.
(Component#getComponentKey() liefert die Namen der Eltern rekursiv
zusammengesetzt).


Die wichtigsten Unterschiede zu Wicket sind:


"build" anstatt constructor:

Damit kann jederzeit ein Teil des Komponentenbaums neu gebaut werden. Es
ist nicht nötig direkt die ganze Page neu zu bauen.


Komponentennamen für Parameter, anstelle von Interfaces:

Ich finde es bei Wicket umständlich und undurchsichtig, dass nicht
einfach einfach die Komponentennamen (die ja sowieso vergeben werden
müssen) als keys für die Parameter benutzt werden.


Alles ist eine Komponente:

Bei Wicket sind die Klassen für Page und Applications keine Komponenten.
Wicket gibt einem auch keine Hilfen zur Hand, um die Seiten zu
Strukturieren.

Das ist mir nicht flexibel genug. Die gesamte Application sollte durch
ein Model definiert werden können.

Mit der Methode "build" lässt sich in Abhängigkeit von einem Model die
_gesamte_ Application bauen. Das ist bei dem gefragten Projekt wichtig,
weil je nach user komplett andere Seiten, oder besser gesagt eine
komplett andere Applikation zur Verfügung stehen können muss.

Timo

Heiner Kücker

unread,
Aug 29, 2005, 5:04:55 PM8/29/05
to
Timo Stamm schrieb

> Wenn ein Request ankommt, wird er durch die Methode "beginRequest" durch
> den Baum weitergeleitet. In jeder Komponente wird die Methode
> "onRequest" aufgerufen, die von einer Komponente (zum Beispiel einem
> Formularfeld) überschrieben werden kann.

Was ist hier der Unterschied zu JSF ?

--
Heiner Kücker
Internet: http://www.heinerkuecker.de

Timo Stamm

unread,
Aug 29, 2005, 7:14:44 PM8/29/05
to
Heiner Kücker wrote:
> Timo Stamm schrieb
>
>>Wenn ein Request ankommt, wird er durch die Methode "beginRequest" durch
>>den Baum weitergeleitet. In jeder Komponente wird die Methode
>>"onRequest" aufgerufen, die von einer Komponente (zum Beispiel einem
>>Formularfeld) überschrieben werden kann.
>
>
> Was ist hier der Unterschied zu JSF ?


Keine Ahnung :)

Objekte/Events rekursiv in einem Baum weiterzureichen ist nichts
besonderes. Wenn bei JSF Objekte rekursiv durch den Komponentenbaum
gereicht werden überrascht mich das nicht.

Von JSF weiss ich nur dass es unglaublich umständlich ist, damit eine
Web-Anwendung umzusetzen, zumindest für meinen Geschmack. Es werden
Taglibs benutzt um die Komponenten in JSPs einzubinden - ich benutze das
Komponentsystem zwar gerade auch in Taglibs, weil ich damit in einer
bestehenden JSP-Anwendung arbeite, gut finde ich das aber nicht.


Ordner/JSP Dateien halte ich für vollkommen ungeeignet, um damit
grössere Anwendungen zu strukturieren. Sowas sollte nicht im Dateisystem
abgelegt werden, sondern da stattfinden, wo man die meiste Kontrolle hat
und auch refaktorieren kann, nämlich im Source.

Ein simples Beispiel:

class TestApp extends AppServlet {
public void build() {
set("/Page1", new Page1());
set("/Page2", new Page2());
set("/Page2/SubPage", new Page3());
}
}


Timo

Stefan Matthias Aust

unread,
Aug 30, 2005, 4:27:41 AM8/30/05
to
Timo Stamm schrieb:

>> Wicket ist zwar ein Komponenten-basiertes System, nicht jedoch
>> Komponenten-orientiert (wie etwa SeaSide) sondern immer noch
>> seitenorientiert.
>
> Das ist wohl der Knackpunkt. Smalltalk kommt aber nicht in Frage.

Dann lass uns das für Java portieren... obwohl, es wird nicht so schick
werden. Der HTML-Renderer

renderOn: html
html
div style: 'background-color: lightblue'; with: [
html text: count; break.
html anchor callback: [self increase]; with: '++'.
html space.
html anchor callback: [self decrease]; with: '--']

lässt sich so nicht direkt umsetzen. Es fehlen die Blöcke und die
Schlüsselwortargumente. Trotzdem, irgendwie ginge das sicherlich:

void render(HtmlCanvas html) {
html.begin("div").style(...);
html.text(count).br();
html.anchor().callback(new Callback() {
public void call() { increase(); }}).with("++");
html.space();
html.anchor().callback(new Callback() {
public void call() { decrease(); }}).with("--");
html.end("div");
}

Wenn reflections okay sind, dann ginge auch:

html.anchor().callback(this, "increase").with("++");

was vielleicht näher am Original ist.

Wie man allerdings am besten continuations in Java umsetzt könnte ich
nicht sagen. Der naive Ansatz wäre Threads zu benutzen, aber ich denke,
das ist keine gute Idee, weil es davon zu wenig gibt. Jeder andere
Ansatz würde aber AFAIK eine Scriptsprache erfordern. Man könnte
vielleicht BeanShell ähnlich wie es mit Rhino passiert ist um
continuations erweitern. Dann würde man die "render"-Methode nicht in
Java sondern in der Scriptsprache schreiben und in Java hätte man quasi
nur den Interpreter geschrieben. Das ist der Ansatz von SISC.

> Ich würde ungern an Wicket vorbei programmieren. Es wäre gut, wenn man
> die bestehenden Formular-Komponenten von Wicket dafür benutzen kann.
> Wenn man dafür den Wicket source patchen muss oder tief in die Interna
> greift ist das keine Option, das ist auf lange Sicht mehr Arbeit.

Ich habe mir jetzt das BeanEditor-Beispiel angeschaut aus der
CVS-Version angeschaut:

Ich meine, BeanPanel ist der Startpunkt (Dokumentation habe ich keine
gefunden) und der erbt über AbstractBeanPanel von Panel. Ein Panel ist
etwas, das sich sein Markup wie folgt aus einer HTML-Datei heraussucht:

<html>
...
<wicket:panel>Hallo <span wicket:id="name"></span></wicket:panel>
...
</html>

Alles außerhalb von wicket:panel wird ignoriert und innerhalb werden
ganz normal die mit wicket:id markierten Elemente bearbeitet.

Das BeanPanel hat daher das folgende Markup:

<wicket:panel>
<table>
<span wicket:id="header">header comes here</span>
<tr wicket:id="propertiesList">
<td>
<span wicket:id="displayName">property display name</span>
</td>
<td>
<span wicket:id="editor">property editor panel</span>
</td>
</tr>
</table>
</wicket:panel>

Es gibt einen Kopf und dann eine Tabelle, die eine Liste von
property-Namen und passenden Editoren anzeigt. Über diese Liste wird
die Dynamik geschaffen.

Das BeanPanel sieht so aus:

BeanPanel(String id, BeanModel model) {
super(id, model);
add(newHeader("header", model));
add(new PropertyList("propertiesList",
new BeanPropertiesListModel(model));
}

Und PropertyList (da war jemand nicht konsequent in der
Singular/Plural-Benennung und auch ob da ein Bean davor kommt, ist nicht
einheitlich; schließlich kann man offenbar nur den Header über eine
Factory-Methode in Unterklassen überschreiben, nicht die Liste selbst)
sieht so aus:

class PropertyList extends ListView {
// diese Methode baut die einzelnen Zeilen der Liste
protected void populateItem(ListItem item) {
PropertyMeta propertyMeta = (PropertyMeta) item.getModelObject();
item.add(new Label("displayName", propertyMeta.getDisplayName()));
item.add(newPropertyEditor("editor", propertyMeta));
}
}

wobei newPropertyEditor() eine Factory-Methode des BeanPanel ist und
abhängig vom Typ einen BeanPropertyEditor findet. Das ist erneut eine
Unterklasse von Panel und PropertyInput ist eine konkrete Unterklasse,
die ein Eingabefeld (für Strings, Integer, usw) darstellt:

PropertyInput(String id, PropertyMeta propertyMeta) {
super(id, propertyMeta);
add(new TextField("value", new BeanPropertyModel(propertyMeta), type);
}

dazu gehört dann dieser HTML-Schnipsel:

<wicket:panel><input type="text" wicket:id="value" /></wicket:panel>

Man sieht also, eine einfache Dynamik über einen ListView funktioniert,
doch man braucht zwingend begleitende HTML-Dateien. Der ListView muss
natürlich nicht immer eine Tabelle benutzen, er wiederholt ein
beliebiges HTML-Element.

Würde man etwa span-Elemente darstellen wollen und nach jedem dritten
Element einen Zeilenumbruch durch <br> erzwingen wollen, könnte man wohl
ListView#renderItem(item) überschreiben.

> Der _Inhalt_ der Fehlermeldungen stammt aus properties Dateien. Die
> Fehlermeldung wird aber von der Komponente FormComponentFeedbackBorder
> gerendert, die auch eine eigene Template hat.
>
> Deshalb meine Meinung, dass nicht zwangsweise jede gerenderte Komponente
> in der Page Template auftauchen muss.

Nein, aber entweder muss ein Panel referenziert werden oder aber ein Border.

> Ahh, das BeanEditor-Beispiel gab es in 1.0 noch nicht.
>
> Leider wären Beans jedoch auch keine Lösung.

Du sollst auch keine Beans nehmen, sondern schauen, wie die da den
Editor dynamisch gebaut haben (siehe oben).

>> Erzähle bitte mehr darüber.
>
> Puh, das ist eigentlich zu früh und auch nicht für die public domain
> gedacht. Aber was darüber erzählen kann ich schon.
>
> Es ist ein komplett komponentenorientierter Ansatz. Der Komponentenbaum
> befindet sich in der Session.
>
>
> Jede Komponente hat eine Methode "build", in der mit "set" Kinder
> hinzugefügt werden können. Diese Methode wird oft vom User
> implementiert, kann aber auch von komplexeren Komponenten implementiert
> sein. Bei einer Listenkomponente sieht es vereinfacht so aus:
>
> class List<T> extends Component {
> private Collection<T> model;

Endlich mal jemand, der Java 5 benutzt!

> // ...
> public void build() {
> for (T t : model) {
> set(new String(i++), populate(t));
> }

set finde ich komisch. Ich hätte add() oder put() akzeptiert.

> Die Methode "render" wird mit einem PrintWriter als Argument aufgerufen,
> und macht als default nichts anderes als in allen Kindern wieder
> "render" aufzurufen.
>
> In einer StringComponent sieht "render" dann so aus:
>
> public final void render(PrintWriter out) {
> out.print(str);
> }
>
>
> Als Template habe ich JSP und einfache Textdateien ausprobiert. Bisher
> allerdings nur "flach", d.h. nur die direkten Kinder können in der
> Template angesprochen werden. Es spricht aber nichts dagegen, auch
> tiefer in den Komponentenbaum einzugreifen. Auch eine Template wie bei
> Wicket wäre möglich, interessiert mich aber nicht weiter.

Was spricht dagegen, das HTML direkt zu erzeugen? Es heißt zwar immer,
dann können ja die armen Grafikdesigner kein HTML-Layout bauen, aber
meine Erfahrung ist meist, dass die bestenfalls ein Photoshop-Bild
abliefern und das HTML dann doch an den Entwicklern kleben bleibt... und
dann würde ich natürlich schon gerne alle Möglichkeiten der Abstraktion
der der Vereinfachung durch Java benutzen und das HTML quasi
programmieren (so wie oben gezeigt).

Heiner Kücker

unread,
Aug 30, 2005, 11:11:19 AM8/30/05
to
"Stefan Matthias Aust" <nob...@3plus4.de> schrieb im Newsbeitrag news:df1gu8$4vs$1...@online.de...
> Du brauchst eine zugehörige Java-Klasse, die von einer Wicket-Klasse
> namens WebPage erbt, und jetzt definiert, wodurch die markierten
> Elemente ersetzt werden sollen:
>
> class MyPage extends WebPage {
> MyPage(String id) {
> super(id);
> add(new ListView("liste", getData()) {
> protected void populateItem(ListItem listItem) {
> add(new Label("whatever");
> }
> });
> }
> private List<Item> getData() {
> //holt das zeug irgendwie aus der DB
> }
> }

Furchtbar. Das soll ne gute Technologie sein ?

"Timo Stamm" <timo....@arcor.de> schrieb im Newsbeitrag
news:43132e55$0$24157$9b4e...@newsread4.arcor-online.net...


> Nachdem das rekursive "beginRequest" durchgelaufen ist, wird
> "beginAction" gestartet. Auch hier wieder rekursiv, analog zu
> "onRequest" wird "onAction" in jeder Komponente aufgerufen. Hier kann
> zum Beispiel eine Button- oder Link-Komponente eine Methode aufrufen,
> die der User implementieren kann. Die Trennung zu onRequest ist
> sinnvoll, damit zum Beispiel alle Formularfelder das Model aktualisiert
> haben bevor die Aktion ausgeführt wird.


Könnte man die Request-Werte nicht über Reflection in das Model pumpen ?
HiearchicBeans ?

Timo Stamm schrieb


> Ordner/JSP Dateien halte ich für vollkommen ungeeignet, um damit
> grössere Anwendungen zu strukturieren. Sowas sollte nicht im Dateisystem
> abgelegt werden, sondern da stattfinden, wo man die meiste Kontrolle hat
> und auch refaktorieren kann, nämlich im Source.
>
> Ein simples Beispiel:
>
> class TestApp extends AppServlet {
> public void build() {
> set("/Page1", new Page1());
> set("/Page2", new Page2());
> set("/Page2/SubPage", new Page3());
> }
> }

Scheinbar willst Du das Layout auf Java-Sourcen abbilden.

> set("/Page2/SubPage", new Page3());

String-Keys, keine Compiler-Prüfung. Das könnte eine Fehlerquelle sein.

Wenn man sich schon entscheidet, Java-Source als Träger
des Layouts zu verwenden, als Alternative zu HTML, XHTML, XML (XUL-Prinzip),
so sollte doch die Java-Source wenigstens ein bisschen visuell sein.

Also nicht wie bei AWT/Swing addXyz().

Wie wäre es mit ein bisschen Reflection oder Quellcode-Analyse (oder ab Java5 Annotations):

Beispiel-Layout:

links ein Menübaum, rechts eine TabPane mit mehreren Forms:

class Page1 extends FrameworkHorzontalPane {
MenuTree menuTree;
TabPane1 tabPane;
}

class TabPane1 extends FrameworkTabPane {
FormPane1_1 formPane1_1;
FormPane1_2 formPane1_2;
FormPane1_3 formPane1_3;
FormPane1_4 formPane1_4;
}

class FormPane1_1 extends FrameworkFormPane {
Textfield name;
...
}

und so weiter.

Ich sehe gerade, alles ziemlich scattered (Funktionalität im Code verstreut).
Hier würde wahrscheinlich so etwas wie mein Codegenerator für hierarchische
Strukturen helfen.

Den Code würde dann der Framework-Renderer über Reflection
(liefert Reflection eigentlich die Attribute in der Reihenfolge wie im Source?)
oder Code-Analyse oder Annotations untersuchen und danach
die Seite auslayouten.

Diese Lösung würde ich einem vertrackten Registry-Mechanismus vorziehen.

--
Heiner Kücker
Internet: http://www.heinerkuecker.de http://www.heiner-kuecker.de
JSP WorkFlow PageFlow Page Flow FlowControl Navigation: http://www.control-and-command.de
Java Expression Formula Parser: http://www.heinerkuecker.de/Expression.html
Domain Specific Languages http://www.heinerkuecker.de/DomainParser.html

Stefan Matthias Aust

unread,
Aug 30, 2005, 1:35:07 PM8/30/05
to
Heiner Kücker schrieb:

>> class MyPage extends WebPage { [...]


>
> Furchtbar. Das soll ne gute Technologie sein ?

Was ist daran furchtbar? Das ist ganz normaler Java-Code. So sieht Java
nun mal aus :) Und wenn man in Java Webanwendungen schreiben will, dann
finde ich, man soll auch Java benutzen und nicht irgendwelche
Merkwürdigkeiten wie JSP und EL, die nochmal wieder besondere Werkzeuge
erfordern (IDEA 5 ist da allerdings ziemlich gut).

> Könnte man die Request-Werte nicht über Reflection in das Model pumpen ?
> HiearchicBeans ?

[...]

> String-Keys, keine Compiler-Prüfung. Das könnte eine Fehlerquelle sein.

Wie nun - Typsicher oder Reflections?

> Beispiel-Layout:
>
> links ein Menübaum, rechts eine TabPane mit mehreren Forms:
>
> class Page1 extends FrameworkHorzontalPane {
> MenuTree menuTree;
> TabPane1 tabPane;
> }

Wo siehtst du denn das Links und das Rechts? Ich würde da mindestens
irgendwo eine Methode ähnlich wie

void render(Html html) {
html
.css("#tree", "float:left; width:200px")
.css("#tabs", "margin-left: 220px")
.div("#tree").render(menuTree).end()
.div("#tabs").render(tabPane).end();
}

erwarten.

> class TabPane1 extends FrameworkTabPane {
> FormPane1_1 formPane1_1;
> FormPane1_2 formPane1_2;
> FormPane1_3 formPane1_3;
> FormPane1_4 formPane1_4;
> }

Und hier sowas wie

void render(Html html) {
html.css(".tabstrip", "...");
html
.ul("tabstrip")
.li(selectClass(formPanel1_1))
.a(selectUrl(formPanel1_1)).text(formPanel1_1.getTitle()).end()
.end()
...
.end()
.div("tabbody").render(selectedPanel).end();
}
private String selectClass(FormPanel p) {
return p == selectedPanel ? "selected" : "normal";

Heiner Kücker

unread,
Aug 30, 2005, 3:49:21 PM8/30/05
to
Stefan Matthias Aust schrieb
> Heiner Kücker schrieb:

>> String-Keys, keine Compiler-Prüfung. Das könnte eine Fehlerquelle sein.
>
> Wie nun - Typsicher oder Reflections?

Typsicher im Anwendungscode, weil fehleranfällig.
Reflection im Framework (geteste Black-Box).

>> Beispiel-Layout:
>>
>> links ein Menübaum, rechts eine TabPane mit mehreren Forms:
>>
>> class Page1 extends FrameworkHorzontalPane {
>> MenuTree menuTree;
>> TabPane1 tabPane;
>> }
>
> Wo siehtst du denn das Links und das Rechts? Ich würde da mindestens
> irgendwo eine Methode ähnlich wie
>
> void render(Html html) {
> html
> .css("#tree", "float:left; width:200px")
> .css("#tabs", "margin-left: 220px")
> .div("#tree").render(menuTree).end()
> .div("#tabs").render(tabPane).end();
> }
>
> erwarten.

Ich hatte den verrückten Gedanken, dass der Quellcode
vom Layout her dem Bildschirmlayout ähnelt.
(Sch. Proportionalschriften)

+-----------------------------------------------+
| -+-Menu1 | Tab1 | Tab2 | Tab3 | Tab4 |
| | |-----------------------------+
| +-Menu2 | Text1 |
| | | |
| +-Menu2_1 | |
| | |
+-----------------------------------------------+

Ist aber wahrscheinlich Unsinn. Da wird jeder sagen, schau mal
VB an.

Aber eigentlich liegt doch das Problem darin, dass es einmal den Java-Code
und
zum anderen Sachen wie HTML, JavaScript usw. gibt.

Aber GUIs, welche nur nativ die Basis-Sprache benutzen sind auch nicht das
Wahre.
Warum gibt es sonst GUI-Editoren, XUL usw.?

Es gibt da auch dieses W4Toolkit. Sah eigentlich super aus.

Eine Idee noch am Rande:

Angenommen, die Page besteht aus einem Komponentenbaum und jede Komponente
hat seinen Renderer.
Der Renderer realisiert eine Kombination aus individuellen (HTML) und
globalen (CSS)
View-Optionen. Also muss globales und individuelles clever vermengt werden.

Ein GUI-Designer könnte nun eine einzelne Komponente im Test-Mode (Model
liefert
Testdaten for-Schleife 1 bis 10 usw) mit Design-Attributen versehen.

Der Anwendungsentwickler oder der Designer baut die Komponenten zu Pages
zusammen.

Der Designer versieht die Page mit globalen Design-Attributen.

Der Anwendungsentwickler klebt den Anwendungscode dahinter.

Jede Komponente müsste so eine Art Testbetriebsart haben, welche in einem
Container
(WebApp für Develop/Debug) läuft und sich allein im Browser anzeigen lässt.

Attribut-Änderungen müssten ohne neues Deployment wirksam werden.

--
Heiner
www.heinerkuecker.de


Timo Stamm

unread,
Aug 30, 2005, 4:05:55 PM8/30/05
to
Heiner Kücker wrote:
> Furchtbar. Das soll ne gute Technologie sein ?

Nein, soll es nicht. Mein Ziel ist die Anforderungen die mir regelmässig
begegnen unter Vernachlässigung von jedem Dogmatismus und Gewohnheiten
mit minimalem Aufwand umsetzen zu können.

> Timo Stamm schrieb
>
>>Ordner/JSP Dateien halte ich für vollkommen ungeeignet, um damit
>>grössere Anwendungen zu strukturieren. Sowas sollte nicht im Dateisystem
>>abgelegt werden, sondern da stattfinden, wo man die meiste Kontrolle hat
>>und auch refaktorieren kann, nämlich im Source.
>>
>>Ein simples Beispiel:
>>
>> class TestApp extends AppServlet {
>> public void build() {
>> set("/Page1", new Page1());
>> set("/Page2", new Page2());
>> set("/Page2/SubPage", new Page3());
>> }
>> }
>
>
> Scheinbar willst Du das Layout auf Java-Sourcen abbilden.

Die Struktur, die sonst durch Verzeichnisstrukturen definiert wird, ja.
Verzeichnisstrukturen lassen sich halt nicht dynamisch abhängig von
Daten in einer DB ändern. Zumindest wäre das unsinnig.

>> set("/Page2/SubPage", new Page3());
>
>
> String-Keys, keine Compiler-Prüfung. Das könnte eine Fehlerquelle sein.

Nein. Das ist der _einzige_ Punkt an dem die Url festgelegt wird, unter
der die Seite zu erreichen ist. Darauf wird nie explizit zugegriffen.

Genausogut könntest du sagen dass der String Wert folgender "Konstante"
eine Fehlerquelle ist:

static final foo = "mein hut hat drei ecken";

> Wenn man sich schon entscheidet, Java-Source als Träger
> des Layouts zu verwenden, als Alternative zu HTML, XHTML, XML (XUL-Prinzip),
> so sollte doch die Java-Source wenigstens ein bisschen visuell sein.
>
> Also nicht wie bei AWT/Swing addXyz().
>
> Wie wäre es mit ein bisschen Reflection oder Quellcode-Analyse (oder ab Java5 Annotations):

Tja, genau das hat eine alte Version gemacht. Das habe ich aber
verworfen, weil es einfach nicht flexibel genug ist und sich für mich
als Sackgasse erwiesen hat.


Timo

Heiner Kücker

unread,
Aug 30, 2005, 4:36:18 PM8/30/05
to
Timo Stamm schrieb

> Heiner Kücker wrote:
> > Wie wäre es mit ein bisschen Reflection oder Quellcode-Analyse (oder ab Java5 Annotations):
>
> Tja, genau das hat eine alte Version gemacht. Das habe ich aber
> verworfen, weil es einfach nicht flexibel genug ist und sich für mich
> als Sackgasse erwiesen hat.

Ok, ich dachte natürlich an statische Layouts (ausser Tabellen-Zeilen-Anzahl usw.).
Vielleicht hätte ich das Subjekt dieses Threads lesen sollen ?

Timo Stamm

unread,
Aug 30, 2005, 4:43:43 PM8/30/05
to
Stefan Matthias Aust wrote:

> [SeaSide]

Das muss ich mir erstmal genauer anschauen. Zu den anderen Themen schonmal:


> Wie man allerdings am besten continuations in Java umsetzt könnte ich
> nicht sagen. Der naive Ansatz wäre Threads zu benutzen, aber ich denke,
> das ist keine gute Idee, weil es davon zu wenig gibt. Jeder andere
> Ansatz würde aber AFAIK eine Scriptsprache erfordern. Man könnte
> vielleicht BeanShell ähnlich wie es mit Rhino passiert ist um
> continuations erweitern. Dann würde man die "render"-Methode nicht in
> Java sondern in der Scriptsprache schreiben und in Java hätte man quasi
> nur den Interpreter geschrieben. Das ist der Ansatz von SISC.

Ich habe ehrlich gesagt noch nicht verstanden was mit Continuations
gemeint ist. Was du Continuation nennst scheint etwas anderes zu sein
als das was man darüber lesen kann.

Das beschriebene Problem im Thread "Was bringen continuation-based
Web-Rahmenwerke?" kenne ich natürlich.

Mit Threads stelle ich es mir am saubersten vor, aber man bräuchte
mindestens einen Thread pro user.

In ActionScript habe ich mal ein ein ähnliches Problem gehabt und für
jeden Schritt im Arbeitsablauf ein Objekt angelegt. Es war sehr
hässlich, aber brauchbar.

> Ich habe mir jetzt das BeanEditor-Beispiel angeschaut aus der

> CVS-Version angeschaut: [...]

Danke für die Infos. Ich werde wohl erst mal mit Wicket arbeiten um mehr
Erfahrungen zu sammeln.


> [...]


>> // ...
>> public void build() {
>> for (T t : model) {
>> set(new String(i++), populate(t));
>> }
>
>
> set finde ich komisch. Ich hätte add() oder put() akzeptiert.

"add" halte ich mir frei für Komponenten, bei denen kein Name für ein
Kind vergeben werden muss um von einer Template darauf zuzugreifen. Also
zum Beispiel die Listenkomponente.

"set" habe ich genommen, weil die Komponente für einen bestimmten
Bezeichner in der Template gesetzt wird, also nach dem Motto: "setze
(set) für diese id diese Komponente".

"put" klingt so, als könnte man beliebig viele Komponenten hinzufügen,
und das ist halt nicht der Fall wenn eine Template vorhanden ist.

> [Template]


>
> Was spricht dagegen, das HTML direkt zu erzeugen? Es heißt zwar immer,
> dann können ja die armen Grafikdesigner kein HTML-Layout bauen, aber
> meine Erfahrung ist meist, dass die bestenfalls ein Photoshop-Bild
> abliefern und das HTML dann doch an den Entwicklern kleben bleibt... und
> dann würde ich natürlich schon gerne alle Möglichkeiten der Abstraktion
> der der Vereinfachung durch Java benutzen und das HTML quasi
> programmieren (so wie oben gezeigt).


Die konsequente Trennung von HTML und Programm finde ich nur sinnvoll,
wenn vorauszusehen ist dass das HTML öfter geändert wird als das
Programm. Das wäre zum Beispiel der Fall, wenn man ein Shop-System
schreibt und als OS veröffentlicht: Tausende laden es herunter und
ändern die Template - nur ein Bruchteil der Änderungen finden im
Programm statt.

Neben Photoshop-Dateien bekomme ich auch sehr oft fertige HTML Vorlagen.
Ich denke du kannst dir vorstellen, dass das HTML nicht unbedingt das
schönste ist und ich mir dann gerne spare, das nachzuprogrammieren, es
lieber per copy & paste zerlege und "blind" benutze.

Momentan benutze ich auch garkeine Template für die Komponenten (nur für
das Grundgerüst der Seiten). Das HTML wird ganz barbarisch so konstruiert:

public void render(PrintWriter out) {
out.println("<td>");
super.render(out);
out.println("</td>");
}

Das funktioniert, bei Attributen fängt es aber schon an, unschön zu werden.

Auf Dauer sollten die Tags also anders konstruiert werden.Es gibt das
Element Construction Kit (noch nicht angesehen). Von Mortbay habe ich im
Jetty Release auch ein schlankes Paket für HTML Konstruktion gefunden.

Es wäre zu früh sich jetzt schon für etwas Komplexeres zu entscheiden.


Timo

Stefan Matthias Aust

unread,
Aug 31, 2005, 7:39:24 AM8/31/05
to
Heiner Kücker schrieb:

> Typsicher im Anwendungscode, weil fehleranfällig.
> Reflection im Framework (geteste Black-Box).

Das klingt vernünftig.

> Ich hatte den verrückten Gedanken, dass der Quellcode
> vom Layout her dem Bildschirmlayout ähnelt.

Aber irgendwie musst du doch das Layout angeben.

> (Sch. Proportionalschriften)

Dann nimm einen anderen Newsreader/Editor :) Ich habe hier "richtige"
Schrift und dein Beispiel sieht falsch aus...

> Aber eigentlich liegt doch das Problem darin, dass es einmal den Java-Code
> und zum anderen Sachen wie HTML, JavaScript usw. gibt.

Eben. Daher möglichst wenig anderes als Java-Code im eigenen Programm.

> Aber GUIs, welche nur nativ die Basis-Sprache benutzen sind auch nicht das
> Wahre.

Wieso nicht?

> Warum gibt es sonst GUI-Editoren, XUL usw.?

Keine Ahnung, die meisten sind eh schlecht :)

> Es gibt da auch dieses W4Toolkit. Sah eigentlich super aus.

Solange, bis irgendwas im Layout nicht so ist wie du willst und du doch
dies HTML-Ebene debuggen musst. Solange wir nicht wie bei
Programmiersprachen mit source-level-debuggern erreicht haben, dass wir
uns von einer Sprache wie HTML komplett lösen können, ist es IMHO meist
kontraproduktiv, sich davor zu verschließen.

> Eine Idee noch am Rande:
>
> Angenommen, die Page besteht aus einem Komponentenbaum und jede Komponente
> hat seinen Renderer.

So hatte ich mir das vorgestellt.

> Der Renderer realisiert eine Kombination aus individuellen (HTML) und
> globalen (CSS)
> View-Optionen.

Das hatte ich versucht anzudeuten. Mein Html-Objekt sammelt die
CSS-Informationen und packt sie automaisch in den Header.

> Ein GUI-Designer könnte nun eine einzelne Komponente im Test-Mode (Model
> liefert
> Testdaten for-Schleife 1 bis 10 usw) mit Design-Attributen versehen.

Ja, eine Komponente sollte einzelnd instantiierbar sein. Eine gute
Sprache unterscheidet sowieso nicht zwischen Laufzeit und Entwurfszeit
sondern läuft immer und damit wäre das dann auch ohne weitere
Verrenkungen möglich :)

> Der Anwendungsentwickler oder der Designer baut die Komponenten zu Pages
> zusammen.
>
> Der Designer versieht die Page mit globalen Design-Attributen.
>
> Der Anwendungsentwickler klebt den Anwendungscode dahinter.

Ich würde ja vermuten, dass zuerst das Design steht und dann erst das
ganze in komponenten aufgeteilt wird, aber ansonsten, ja.

> Jede Komponente müsste so eine Art Testbetriebsart haben, welche in einem
> Container
> (WebApp für Develop/Debug) läuft und sich allein im Browser anzeigen lässt.

Guck dir mal Seaside an... da geht das soweit, dass man zur Laufzeit
(denn es gibt nur diese) direkt im Browser in eine Mini-Version der
Entwicklungswerkzeuge wechseln kann und einzelne Methoden oder
Komponenten ändern kann.

> Attribut-Änderungen müssten ohne neues Deployment wirksam werden.

Sowieso.

Heiner Kücker

unread,
Aug 31, 2005, 2:31:16 PM8/31/05
to
Stefan Matthias Aust schrieb
> Heiner Kücker schrieb:
> > Aber GUIs, welche nur nativ die Basis-Sprache benutzen sind auch nicht das
> > Wahre.
>
> Wieso nicht?

Die direkte Abbildung von GUI-Layouts im Quellcode ist unübersichtlich und indirekt.

> Guck dir mal Seaside an... da geht das soweit, dass man zur Laufzeit

Schade, Smalltalk beherrsche ich nicht.

--
Heiner Kücker
Internet: http://www.heinerkuecker.de

Stefan Matthias Aust

unread,
Sep 1, 2005, 5:49:32 AM9/1/05
to
Timo Stamm schrieb:

> Ich habe ehrlich gesagt noch nicht verstanden was mit Continuations
> gemeint ist. Was du Continuation nennst scheint etwas anderes zu sein
> als das was man darüber lesen kann.

Hm, das sollte eigentlich nicht nein. Ich dachte, ich hätte das so
beschrieben, wie es in Scheme definiert ist (wo AFAIK der Begriff herkommt).

Dieses Beispiel zeigt, wie man continuations benutzen kann, um das
Programm als vorgesehen weiterlaufen zu lassen.

(call/cc (lambda (exit)
(map (lambda (x) (if (negative? x) (exit x) x))
'(1 2 -3 4 5))))

"exit" ist eine continuation, eine Funktion, die den Rest des Programms
repräsentiert. Das "map" würde normalerweise die angegebene anonyme
Funktion für jedes Element der ebenfalls angegebenen Liste bearbeiten
und die "normale Zukunft" wäre, die Liste unverändert zurückzugeben. Nun
wird allerdings bei der negativen Zahl einfach die Verabeitung
abgebrochen und -3 ist das neue Ergebnis.

Dies entspricht in Java einem try/catch

Object result;
ExitException exit = new ExitException();
try {
result = map(new lambda() {
public Object apply(Object o) {
if (((Integer) o).intValue() < 0) exit.throwWith(o);
return o;
}, list(1, 2, -3, 4, 5));
} catch (ExitException e) {
if (e != exit) throw e;
result = e.getValue();
}
return result;

mit

class ExitException extends RuntimeException {
private Object value;
public void throwWith(Object value) {
this.value = value;
throw this;
}
}

Was Java jedoch nicht mehr kann, ist das Aufheben einer Continuation und
das mehrfache Benutzen:

(define r #f)
(+ 1 (call/cc (lambda (k) (set! r k) (+ 2 (k 3)))))

Dieser Aufruf liefert 1 + 3 = 4, wenn das "call/cc" wird ja mit dem
Ergebnis 3 beendet. Gleichzeitig wird die continuation in "r" gespeichert.

(r 5)

Dieser Aufruf liefert jetzt 6. Die Auswertung von (+ 1 [...]) wird
erneut fortgesetzt und diesmal liefert das "call/cc" die übergebene 5.
Das funktioniert beliebig oft.

Mit diesem Wissen kann man sich jetzt coroutinen bauen, Funktionen, die
man anhalten und wieder fortsetzen kann.

(define-macro (coroutine . body)
`(letrec ((local-control-state (lambda () ,@body))
(resume (lambda (c)
(call/cc
(lambda (k)
(set! local-control-state k)
(c))))))
local-control-state))

Dieses fiese Makro definiert eine lokale Variable "local-control-state"
mit die eine namenlosen Funktion, die das, was die coroutine ausführen
soll, enthält und eine Funktion "resume" mit einem Argument: Einer
continuation. Im Rumpf der Coroutine kann man jetzt resume aufrufen, um
eine andere coroutine fortzusetzen. Ergebnis des Makros ist die
Funktion, die in local-control-state definiert wurde, also der Rumpf der
Coroutine.

Definiert man dies

(letrec ((a (coroutine (print 1) (resume b) (print 3)))
(b (coroutine (print 2) (resume a) (print 4))))
(a))

sollte man eigentlich 1, 2, 3 und 4 sehen. Falls nicht, habe ich einen
Fehler beim vereinfachen der Makro-Definition gemacht :)

In Java könnte man Coroutinen mit Hilfe von Threads realisieren, die
aufeinander warten.

class Coroutine extends Thread {
public void resume(Coroutine c) {
synchronized(c) {
c.notify();
}
synchronized(this) {
wait();
}
}
}
Coroutine a;
Coroutine b;
a = new Coutine() {
public void run() {
print(1); resume(b); print(3);
}
};
b = new Coutine() {
public void run() {
print(2); resume(a); print(4);
}
};

Aber das ist natürlich viel schwergewichtiger als eine continuation zu
benutzen.

>> set finde ich komisch. Ich hätte add() oder put() akzeptiert.
>
> "add" halte ich mir frei für Komponenten, bei denen kein Name für ein
> Kind vergeben werden muss um von einer Template darauf zuzugreifen. Also
> zum Beispiel die Listenkomponente.
>
> "set" habe ich genommen, weil die Komponente für einen bestimmten
> Bezeichner in der Template gesetzt wird, also nach dem Motto: "setze
> (set) für diese id diese Komponente".
>
> "put" klingt so, als könnte man beliebig viele Komponenten hinzufügen,
> und das ist halt nicht der Fall wenn eine Template vorhanden ist.

Ach so, ich dachte, das ginge mit beliebig vielen.

> Neben Photoshop-Dateien bekomme ich auch sehr oft fertige HTML Vorlagen.
> Ich denke du kannst dir vorstellen, dass das HTML nicht unbedingt das
> schönste ist und ich mir dann gerne spare, das nachzuprogrammieren, es
> lieber per copy & paste zerlege und "blind" benutze.

Ich hätte jetzt argument, dass das HTML so schlecht strukturiert ist,
dass man das eh nochmal "richtig" nachbauen will und daher das fertige
HTML auch nicht besser ist als ein Bild.

> Momentan benutze ich auch garkeine Template für die Komponenten (nur für
> das Grundgerüst der Seiten). Das HTML wird ganz barbarisch so konstruiert:
>
> public void render(PrintWriter out) {
> out.println("<td>");
> super.render(out);
> out.println("</td>");
> }
>
> Das funktioniert, bei Attributen fängt es aber schon an, unschön zu werden.

Schau dir meine Idee für den Html-Renderer an, dort könnte man sowas machen:

html.td("class", "simple", "colspan", 4);

oder aber, wenn du's noch statischer haben willst:

html.td().clazz("simple").colspan(4);

was mir aber zu viel Arbeit wäre, da man dann für jedes Element eine
eigene Klasse bräuchte und diverse Methode implementieren müsste.

Ein Kompromiss wäre vielleicht

html.attribute("class", "simple").td()

Timo Stamm

unread,
Sep 2, 2005, 9:58:13 AM9/2/05
to
Stefan Matthias Aust wrote:
> Timo Stamm schrieb:
>
>> Ich habe ehrlich gesagt noch nicht verstanden was mit Continuations
>> gemeint ist. Was du Continuation nennst scheint etwas anderes zu sein
>> als das was man darüber lesen kann.
>
>
> Hm, das sollte eigentlich nicht nein. Ich dachte, ich hätte das so
> beschrieben, wie es in Scheme definiert ist (wo AFAIK der Begriff
> herkommt).

Tja, ich hatte bisher nur einen (schlechten) Artikel über Python und
Continuations gelesen (das Modul wurde scheinbar aus Python wieder
entfernt?).

Das habe ich falsch verstanden.

Ich verstehe langsam was die Continuations bei Web-Anwendungen bringen.
Um das ganze state management muss man sich nicht kümmern (wie bei einer
MVC Web-Anwendung) weil es nativ stattfindet.

Dazu habe ich einen (meiner Meinung nach sehr guten) Artikel bei IBM
gefunden: http://www-128.ibm.com/developerworks/library/j-contin.html

> Definiert man dies
>
> (letrec ((a (coroutine (print 1) (resume b) (print 3)))
> (b (coroutine (print 2) (resume a) (print 4))))
> (a))
>
> sollte man eigentlich 1, 2, 3 und 4 sehen. Falls nicht, habe ich einen
> Fehler beim vereinfachen der Makro-Definition gemacht :)
>
> In Java könnte man Coroutinen mit Hilfe von Threads realisieren, die
> aufeinander warten.
>
> class Coroutine extends Thread {
> public void resume(Coroutine c) {
> synchronized(c) {
> c.notify();
> }
> synchronized(this) {
> wait();
> }
> }
> }
> Coroutine a;
> Coroutine b;
> a = new Coutine() {
> public void run() {
> print(1); resume(b); print(3);
> }
> };
> b = new Coutine() {
> public void run() {
> print(2); resume(a); print(4);
> }
> };
>
> Aber das ist natürlich viel schwergewichtiger als eine continuation zu
> benutzen.


Du meintest ja schon das Threads nur begrenzt zur Verfügung stehen. Aber
ich fände das auch einfach _zu_ schwergewichtig.

Mit dieser Implementation von Continuations bist du wahrscheinlich
wesentlich eher bei unwartbarem Code angelangt bevor eine MVC Anwendung
an die Grenzen von MVC stossen würde.

>> Neben Photoshop-Dateien bekomme ich auch sehr oft fertige HTML Vorlagen.
>> Ich denke du kannst dir vorstellen, dass das HTML nicht unbedingt das
>> schönste ist und ich mir dann gerne spare, das nachzuprogrammieren, es
>> lieber per copy & paste zerlege und "blind" benutze.
>
>
> Ich hätte jetzt argument, dass das HTML so schlecht strukturiert ist,
> dass man das eh nochmal "richtig" nachbauen will und daher das fertige
> HTML auch nicht besser ist als ein Bild.

Momentan betrachte ich das HTML als überhaupt nicht strukturiert. Ich
sehe es einfach nur als Text.

Natürlich ist das keine Lösung auf Dauer. Aber es steht für mich fest
dass ich mich auf keinen Fall auf eine bestimmte Methode (sei es ein
Template-System, DOM oder ein simples Konstruktionskit in Java)
festlegen möchte. Der kleinste gemeinsame Nenner ist Text - ein
PrintWriter schien mir deshalb als "canvas" gut geignet.

Callbacks sind in render() dann natürlich nicht möglich. Der PrintWriter
schreibt in den Stream. Was einmal im Stream steht, lässt sich nicht
mehr beeinflussen - es ist unter Umständen schon beim Client.


> Schau dir meine Idee für den Html-Renderer an, dort könnte man sowas
> machen:

> html.td("class", "simple", "colspan", 4);
>
> oder aber, wenn du's noch statischer haben willst:
>
> html.td().clazz("simple").colspan(4);
>
> was mir aber zu viel Arbeit wäre, da man dann für jedes Element eine
> eigene Klasse bräuchte und diverse Methode implementieren müsste.
>
> Ein Kompromiss wäre vielleicht
>
> html.attribute("class", "simple").td()

Methodenaufrufe direkt aneinander zu schreiben finde ich in diesem Fall gut.

Bei Java 1.4 hätte das mit folgenden Klassen nicht funktioniert:

class Tag() {
public Tag attribute(String name, String value) ...
}

class Td() extends Tag {
public Td colspan(int i) ...
}


Die Methode attribute() gibt ein Tag zurück und colspan() lässt sich
nicht aufrufen. Mir ist erst vor kurzen aufgefallen, dass man seit Java
1.5 den Rückgabewert erweitern kann. Das hatte mich bisher mächtig gestört.

Dafür muss man natürlich die Methoden überschreiben - auch wieder störend.


Stefan Matthias Aust wrote:
>
> Dann lass uns das für Java portieren... obwohl, es wird nicht so schick
> werden. Der HTML-Renderer
>
> renderOn: html
> html
> div style: 'background-color: lightblue'; with: [
> html text: count; break.
> html anchor callback: [self increase]; with: '++'.
> html space.
> html anchor callback: [self decrease]; with: '--']
>
> lässt sich so nicht direkt umsetzen. Es fehlen die Blöcke und die
> Schlüsselwortargumente. Trotzdem, irgendwie ginge das sicherlich:
>
> void render(HtmlCanvas html) {
> html.begin("div").style(...);
> html.text(count).br();
> html.anchor().callback(new Callback() {
> public void call() { increase(); }}).with("++");
> html.space();
> html.anchor().callback(new Callback() {
> public void call() { decrease(); }}).with("--");
> html.end("div");
> }
>
> Wenn reflections okay sind, dann ginge auch:
>
> html.anchor().callback(this, "increase").with("++");
>
> was vielleicht näher am Original ist.


Das begin() und end() stört mich (dich vermutlich auch).


Ich habe mir mal dein Beispiel vorgenommen.


Beim momentanen Stand des Frameworks würde das so aussehen:


class Test extends Component {
int count = 0;
Component increaseLink;
Component increaseLink;
public void build() {
set("l1", increaseLink = new ActionLink<Test>(this, "grösser") {
public void onClick(Test t) { t.count++; }
}));
set("l2", decreaseLink = new ActionLink<Test>(this, "kleiner") {
public void onClick(Test t) { t.count--; }
}));
}
public void render(PrintWriter out) {
out.println("<div style=\"...\">");
out.println(count);
out.println("<br />");
increaseLink.render(out);
out.println(" ");
decreaseLink.render(out);
out.println("</div");
}
}


Mit einem eigenständigen HTML Renderer wäre die Konstruktion des HTML
übersichtlicher:


class Test extends Component {
int count = 0;
Component increaseLink;
Component increaseLink;
public void build() {
set("l1", increaseLink = new ActionLink<Test>(this, "grösser") {
public void onClick(Test t) { t.count++; }
}));
set("l2", decreaseLink = new ActionLink<Test>(this, "kleiner") {
public void onClick(Test t) { t.count--; }
}));
}
public void render(PrintWriter out) {
html = new HTMLCanvas(out);
html.begin("div").style(...);
html.text(count).br();
html.renderComponent(increaseLink);
html.space();
html.renderComponent(decreaseLink);
html.end("div");
}
}


Das ist aber alles viel zu aufwändig für diesen Fall. Hier ist keine
Dynamik gefragt. Das könnte man also mit einer abgeleiteten Komponente
umsetzen, die Reflection benutzt um build() zu machen, also die
Komponenten in den Baum einzufügen, zu initialisieren, etc. (Heiner hat
so etwas vorgeschlagen, halte ich auch nicht für falsch, sollte aber
halt nicht grundsätzlich so sein, um sich Dynamik nicht zu verbauen.)


class Test extends StaticComponent {
int count = 0;
increaseLink = new ActionLink<Test>(this, "grösser") {
public void onClick(Test t) { t.count++; }
});
increaseLink = new ActionLink<Test>(this, "kleiner") {
public void onClick(Test t) { t.count--; }
});
public void render(PrintWriter out) {
html = new HTMLCanvas(out);
html.begin("div").style(...);
html.text(count).br();
html.renderComponent(increaseLink);
html.space();
html.renderComponent(decreaseLink);
html.end("div");
}
}


Das lässt sich mit Annotations noch hübscher machen:

class Test extends StaticComponent2 {
int count = 0;
@actionlink void increase () {
count++;
}
@actionlink void decrease () {
count--;
}
public void render(PrintWriter out) {
HTMLCanvas html = new HTMLCanvas(out);
html.begin("div").style(...);
html.text(count).br();
html.actionlink("grösser", "increase");
html.space();
html.actionlink("kleiner", "decrease");
html.end("div");
}
}


Da fällt mir ein, eine HTML Canvas _Komponente_ wäre natürlich auch
möglich. Diese implementiert render() selbst, überschreibt build() mit
einer Methode die buildHtml() aufruft und ein Objekt übergibt, das ein
einfaches Interface zur Verfügung stellt mit dem sich HTML bauen lässt.

Die Möglichkeit, komplexere Komponenten (ActionLink) dazwischenzusetzen,
kann man ja erlauben:


class Test extends HtmlCanvas /* extends Component */ {
int count = 0;
public void buildHtml(Html h) {
h.begin("div").style(...);
h.text(count).br();
h.component(new ActionLink<Test>(this, "grösser") {
public void onClick(Test t) { t.count++; }
}));
h.space();
component(new ActionLink<Test>(this, "kleiner") {
public void onClick(Test t) { t.count--; }
}));
h.end("div");
}
}


Für die Links lässt sich auch eine Methode benutzen:

class Test extends HtmlCanvas /* extends Component */ {
int count = 0;
public void buildHtml(Html h) {
h.begin("div").style(...);
h.text(count).br();
h.link("grösser", new Callback() {
public void call(HtmlCanvas c) { ((Test)c).count++; }
}));
h.space();
h.link("kleiner", new Callback() {
public void call(HtmlCanvas c) { ((Test)c).count--; }
}));
h.end("div");
}
}


Ohne neues Objekt was man parametrisieren könnte (wie beim ActionLink
oben) braucht man hier aber einen cast für die callback listener.


Ich schätze dass die Lösungen mit Annotations und Reflection und der
HtmlCanvas praktisch wären. Momentan bin ich aber noch nicht damit
fertig, etwas simples für die grundlegende Struktur aufzubauen. Jetzt
schon mit Erweiterungen in eine spezielle Richtung anzufangen wäre zu früh.


Bei Wicket gefällt mir nicht, dass man sich schon festgelegt hat. Eine
möglichst simple Grundlage (weniger als 2000 Zeilen) und Erweiterungen
in verschiedene Richtungen halte ich für besser.


Wenn du Ideen oder Kritik hast: immer her damit!


Timo

Stefan Matthias Aust

unread,
Sep 7, 2005, 4:14:10 AM9/7/05
to
Timo Stamm schrieb:

> Ich verstehe langsam was die Continuations bei Web-Anwendungen bringen.
> Um das ganze state management muss man sich nicht kümmern (wie bei einer
> MVC Web-Anwendung) weil es nativ stattfindet.

Jepp.

> Dazu habe ich einen (meiner Meinung nach sehr guten) Artikel bei IBM
> gefunden: http://www-128.ibm.com/developerworks/library/j-contin.html

Das Cocoon-Beispiel finde ich zu geschwätzig. Kein wirklich
überzeugendes Argument für CPS. Das alte Sprachen für Continuations
nicht gemacht sind finde ich nicht so schlimm. Dann muss man halt neue
Sprachen erfinden. Die funktionale Sprache Alice etwa ist derart
gemacht, dass sie beliebige Funktionen inklusive Umgebung (also
closures) serialisieren (dort wird es picklen genannt), auf einen
anderen Rechner transportieren, dort wieder deserialisieren und
weiterlaufen lassen kann. Alice hat meines Wissens zwar keine
continuations, aber futures und promises und continuations sollten damit
leicht ergänzbar sein, falls ich sie nicht einfach übersehen habe.

> Du meintest ja schon das Threads nur begrenzt zur Verfügung stehen. Aber
> ich fände das auch einfach _zu_ schwergewichtig.

Nun, coroutinen wären damit sehr einfach implementierbar. Und bis 1000
parallele coroutinen sehe ich auch wenig Probleme. Performance ist
wahrscheinlich kein Problem, denn der begrenzende Faktor bei einer
Webanwendung ist meist die Netzverbindung, nicht die VM mit ihren Threads.

Leider kann man bei den modernen JVMs nicht die "native threads"
abschalten und nur "green threads" benutzen oder gar dies je nach Thread
wählen.

Ich sehe daher eigentlich nur die Lösung, dass man sich einen eigenen
Interpreter baut, der eigene Threads verwaltet. Das kann ein
Interpreter für eine coole eigene Sprache sein oder aber - keine Ahnung,
ob das schon mal jemand gemacht hat - eine JVM in Java, die dann class
files lädt und interpretiert.

> Mit dieser Implementation von Continuations bist du wahrscheinlich
> wesentlich eher bei unwartbarem Code angelangt bevor eine MVC Anwendung
> an die Grenzen von MVC stossen würde.

Sehe ich nicht so - die coroutinen sind ja ein Teil des Rahmenwerks den
du in deiner Anwendung möglichst nicht siehst.

> Natürlich ist das keine Lösung auf Dauer. Aber es steht für mich fest
> dass ich mich auf keinen Fall auf eine bestimmte Methode (sei es ein
> Template-System, DOM oder ein simples Konstruktionskit in Java)
> festlegen möchte. Der kleinste gemeinsame Nenner ist Text - ein

Warum nicht? Entscheidungen nicht zu treffen führt häufig zu
über-generellen Lösungen, die schwerer wartbar sind.

> Callbacks sind in render() dann natürlich nicht möglich. Der PrintWriter
> schreibt in den Stream. Was einmal im Stream steht, lässt sich nicht
> mehr beeinflussen - es ist unter Umständen schon beim Client.

Dann abstrahiere nochmal von deinem PrintStream :)

[...]

> Das begin() und end() stört mich (dich vermutlich auch).

Ja, aber die direkte Umsetzung von "with:" wäre

html.div().style("...").with(new Block() {
public void call() {
html.anchor(...);
}
});

und das ist auch nicht schön in Java.

> Das lässt sich mit Annotations noch hübscher machen:
>
> class Test extends StaticComponent2 {
> int count = 0;
> @actionlink void increase () {
> count++;
> }
> @actionlink void decrease () {
> count--;
> }
> public void render(PrintWriter out) {
> HTMLCanvas html = new HTMLCanvas(out);
> html.begin("div").style(...);
> html.text(count).br();
> html.actionlink("grösser", "increase");
> html.space();
> html.actionlink("kleiner", "decrease");
> html.end("div");
> }
> }

Woher weiss denn der HtmlCanvas jetzt, dass "increase" auf "Test" gehen
soll? Ich sehe da keine Verbindung.

> Da fällt mir ein, eine HTML Canvas _Komponente_ wäre natürlich auch
> möglich.

Fände ich nicht so gut, weil ja letztlich jede Komponente (die nicht aus
anderen zusammengesetzt ist) irgendwie HTML ausgeben muss und daher dann
HtmlCavas fast schon die Oberklasse für alles ist und du damit zwei
Verantworlichkeiten - Komponenten verwalten und HTML ausgeben - in einer
Klasse mischt.

Wenn man Mehrfachvererbung oder Mixins hätte, würde ich dir zustimmen
und es dann elegant finden, wenn man einfach die Eigenschaft, HTML
erzeugen zu können, in eine Komponente hineinmixt.

> Für die Links lässt sich auch eine Methode benutzen:
>
> class Test extends HtmlCanvas /* extends Component */ {
> int count = 0;
> public void buildHtml(Html h) {
> h.begin("div").style(...);
> h.text(count).br();
> h.link("grösser", new Callback() {
> public void call(HtmlCanvas c) { ((Test)c).count++; }
> }));
> h.space();
> h.link("kleiner", new Callback() {
> public void call(HtmlCanvas c) { ((Test)c).count--; }
> }));
> h.end("div");
> }
> }

Wo wird eigentlich bei deinen ganzen Beispielen der Wert von Count
gesetzt, wenn diese Komponente erneut für eine Webseite instantiiert
werden muss und ein anderer Wert != 0 gerfordert ist? Oder merkst du
dir etwa die gesamte Komponentenhierarchie in der Session? (Könnte sein,
dass du das schon mal gesagt hast und ich das nur wieder vergessen habe)

> Bei Wicket gefällt mir nicht, dass man sich schon festgelegt hat. Eine
> möglichst simple Grundlage (weniger als 2000 Zeilen) und Erweiterungen
> in verschiedene Richtungen halte ich für besser.

Ich stimme dir zu, es wäre nett, wenn es überhalb des Markups da noch
eine andere generellere Möglichkeit gäbe, die Komponenten darzustellen.
Leider ist das bei Wicket nur die halbe Miete, denn um Komponenten
darzustellen, wird das Markup und die dort eingebetteten ids benutzt.
Man müsste das Verfahren umstellen, dass stattdessen der Komponentenbaum
dargestellt wird und dann hätte man ein komplett andere Rahmenwerk, weil
es dann nicht mehr (einfach) möglich ist, Markup in Form von templates
den Komponenten zuzuordnen.

> Wenn du Ideen oder Kritik hast: immer her damit!

Den Einsatz von annotation finde ich nicht schlecht - Methoden aber
einfach als Strings einzubetten finde ich schon nicht mehr so gut. Wenn
man Java macht, dann sollte man zusehen, das typsicher und vor allen
Dingen refactoring-sicher hinzubekommen.

Timo Stamm

unread,
Sep 13, 2005, 12:46:49 PM9/13/05
to
Stefan Matthias Aust wrote:
> Timo Stamm schrieb:
>
>> Ich verstehe langsam was die Continuations bei Web-Anwendungen
>> bringen. Um das ganze state management muss man sich nicht kümmern
>> (wie bei einer MVC Web-Anwendung) weil es nativ stattfindet.
>
>
> Jepp.
>
>> Dazu habe ich einen (meiner Meinung nach sehr guten) Artikel bei IBM
>> gefunden: http://www-128.ibm.com/developerworks/library/j-contin.html
>
>
> Das Cocoon-Beispiel finde ich zu geschwätzig. Kein wirklich
> überzeugendes Argument für CPS. Das alte Sprachen für Continuations
> nicht gemacht sind finde ich nicht so schlimm. Dann muss man halt neue
> Sprachen erfinden. Die funktionale Sprache Alice etwa ist derart
> gemacht, dass sie beliebige Funktionen inklusive Umgebung (also
> closures) serialisieren (dort wird es picklen genannt), auf einen
> anderen Rechner transportieren, dort wieder deserialisieren und
> weiterlaufen lassen kann. Alice hat meines Wissens zwar keine
> continuations, aber futures und promises und continuations sollten damit
> leicht ergänzbar sein, falls ich sie nicht einfach übersehen habe.


Der Artikel steht in der Kategorie "Java technology". Konkrete Ideen für
die Umsetzung von Continuations in Java habe ich aber komplett vermisst.
Gut fand ich den Artikel nur weil er mir den Sinn von Continuations in
Web-Anwendungen klargemacht hat :)

Eine neue Sprache zu schreiben ist für mich weniger eine Option - für
produktiven Einsatz kommen für mich nur sehr wenige Sprachen in Frage,
da entscheide ich ausgesprochen konservativ.

Was nicht heissen soll dass ich es nicht absolut wichtig fände, sich
andere Sprachen anzuschauen. Da bin ich aber noch nicht mal mit Java
fertig. Ich programmiere erst seit ca. einem Jahr. Alles davor war eher
nicht zielgerichtete Spielerei.


>> Natürlich ist das keine Lösung auf Dauer. Aber es steht für mich fest
>> dass ich mich auf keinen Fall auf eine bestimmte Methode (sei es ein
>> Template-System, DOM oder ein simples Konstruktionskit in Java)
>> festlegen möchte. Der kleinste gemeinsame Nenner ist Text - ein
>
>
> Warum nicht? Entscheidungen nicht zu treffen führt häufig zu
> über-generellen Lösungen, die schwerer wartbar sind.

Deshalb läuft das Teil ja momentan nur nebenbei und nicht in wichtigen
Projekten. Es ist momentan nicht mehr als eine experimentelle Spielwiese
um Erfahrung zu sammeln.


>> Callbacks sind in render() dann natürlich nicht möglich. Der
>> PrintWriter schreibt in den Stream. Was einmal im Stream steht, lässt
>> sich nicht mehr beeinflussen - es ist unter Umständen schon beim Client.
>
>
> Dann abstrahiere nochmal von deinem PrintStream :)

Ich verzichte lieber auf die Möglichkeit, beim Zusammenbauen vom HTML
callbacks benutzen zu können.

Auf einen bestimmten Request-Parameter zu lauschen und davon abhängig
eine Methode aufzurufen ist nicht die Aufgabe des HTML-Renderers,
sondern einer speziellen Komponente.

Das würde auch nicht gut mit Template-Systemen zusammenspielen.

> [...]
>
>> Das begin() und end() stört mich (dich vermutlich auch).
>
>
> Ja, aber die direkte Umsetzung von "with:" wäre
>
> html.div().style("...").with(new Block() {
> public void call() {
> html.anchor(...);
> }
> });
>
> und das ist auch nicht schön in Java.

Dann lieber begin() und end(). Naja, das passt alles nicht wirklich.


>> Da fällt mir ein, eine HTML Canvas _Komponente_ wäre natürlich auch
>> möglich.
>
>
> Fände ich nicht so gut, weil ja letztlich jede Komponente (die nicht aus
> anderen zusammengesetzt ist) irgendwie HTML ausgeben muss und daher dann
> HtmlCavas fast schon die Oberklasse für alles ist und du damit zwei
> Verantworlichkeiten - Komponenten verwalten und HTML ausgeben - in einer
> Klasse mischt.
>
> Wenn man Mehrfachvererbung oder Mixins hätte, würde ich dir zustimmen
> und es dann elegant finden, wenn man einfach die Eigenschaft, HTML
> erzeugen zu können, in eine Komponente hineinmixt.


Stimmt, da sind zu viele Abhängigkeiten. Und andere Problem, s.
folgender Absatz.

> Wo wird eigentlich bei deinen ganzen Beispielen der Wert von Count
> gesetzt, wenn diese Komponente erneut für eine Webseite instantiiert
> werden muss und ein anderer Wert != 0 gerfordert ist? Oder merkst du
> dir etwa die gesamte Komponentenhierarchie in der Session?

Ja, alle Komponenten liegen in der Session.

Bei obigem HtmlCanvas-Beispiel würde jedes einzelne Tag-Objekt in der
Session gehalten. Das scheint mir eine eher blöde Idee zu sein.

Ganze Objekte in der Session zu halten finde ich überzeugender, als sich
die einzelnen Werte aus der Session zu holen und sie wieder dort
abzulegen. Es sollten aber trotzdem nur Objekte dort landen, bei denen
es nötig ist.


>> Bei Wicket gefällt mir nicht, dass man sich schon festgelegt hat. Eine
>> möglichst simple Grundlage (weniger als 2000 Zeilen) und Erweiterungen
>> in verschiedene Richtungen halte ich für besser.
>
>
> Ich stimme dir zu, es wäre nett, wenn es überhalb des Markups da noch
> eine andere generellere Möglichkeit gäbe, die Komponenten darzustellen.
> Leider ist das bei Wicket nur die halbe Miete, denn um Komponenten
> darzustellen, wird das Markup und die dort eingebetteten ids benutzt.
> Man müsste das Verfahren umstellen, dass stattdessen der Komponentenbaum
> dargestellt wird und dann hätte man ein komplett andere Rahmenwerk, weil
> es dann nicht mehr (einfach) möglich ist, Markup in Form von templates
> den Komponenten zuzuordnen.

Das Problem ist doch, dass die Komponenten bei Wicket einmal in Java,
und ein zweites mal in der Template zusammengestellt werden. Diese
Redundanz stört mich. (Ganz abgesehen davon dass es bei den
Anforderungen die ich habe so überhaupt nicht geht.)

Ich finde es ja garnicht schlecht, das HTML von Java zu trennen, aber
das sollte doch auch komponentenweise gehen, nicht bloss seitenweise.
Eine Seite kann man dann ja wieder als eine Komponente betrachten.


>> Wenn du Ideen oder Kritik hast: immer her damit!
>
>
> Den Einsatz von annotation finde ich nicht schlecht - Methoden aber
> einfach als Strings einzubetten finde ich schon nicht mehr so gut. Wenn
> man Java macht, dann sollte man zusehen, das typsicher und vor allen
> Dingen refactoring-sicher hinzubekommen.

Da sehe ich kein so grosses Problem drin wenn es entweder tief in einem
Framework stattfindet wo es gut gekapselt ist oder "am anderen Ende" -
an einer exponierten Stelle. Es kann durchaus Situationen geben in denen
ich es angenehmer finde die Refaktorierbarkeit zu verlieren wenn der
Code dadurch entsprechend kompakter wird und leichter zu verstehen ist.


Timo

Stefan Matthias Aust

unread,
Sep 14, 2005, 4:34:06 AM9/14/05
to
Timo Stamm wrote:

> Eine neue Sprache zu schreiben ist für mich weniger eine Option - für
> produktiven Einsatz kommen für mich nur sehr wenige Sprachen in Frage,
> da entscheide ich ausgesprochen konservativ.

Meist sind derartige "produktive Lösungen" eh (technisch und
konzeptuell) so langweilig, dass die gar keine interessante Sprache
verdienen :)

Will sagen: Mich faszinieren die Konzepte, aber ich will das gar nicht
unbedingt in der Firma einsetzen müssen. Wenn ich da auch bezahlt
werde, länger an einer konventionellen Lösung zu sitzen, habe ich kein
größeres Problem damit. Nur manchmal überkommt es mich, und ich würde
ja schon gerne mit einer Sprache arbeiten, die auch Spass macht und
nicht nur weit verbreitet, viele Bibliotheken und von einer IDE gut
unterstützt ist.

> Was nicht heissen soll dass ich es nicht absolut wichtig fände, sich
> andere Sprachen anzuschauen. Da bin ich aber noch nicht mal mit Java
> fertig. Ich programmiere erst seit ca. einem Jahr. Alles davor war eher
> nicht zielgerichtete Spielerei.

Okay, dann sprechen wir uns in 10 Jahren nochmal :) Dann wird auch dir
Java langweilig geworden sein...

>> html.div().style("...").with(new Block() {
>> public void call() {
>> html.anchor(...);
>> }
>> });
>>
>> und das ist auch nicht schön in Java.
>
> Dann lieber begin() und end(). Naja, das passt alles nicht wirklich.

Oder eben kein Java. Gerade für ein Template-System kann man schnell
ein schickes Lisp o.ä. in ein Projekt einführen. Man sollte allerdings
erstmal Terence Parrs Paper "Enforcing Strict Model-View Separation in
Template Engines" lesen, um zu wissen, was man da warum tut.

Als eine zentrale Aussage in seinem Paper empfinde ich übrigens die
Eigenbeobachtung, dass er da fast soetwas wie eine funktionale Sprache baut.

>> Ich stimme dir zu, es wäre nett, wenn es überhalb des Markups da noch
>> eine andere generellere Möglichkeit gäbe, die Komponenten
>> darzustellen. Leider ist das bei Wicket nur die halbe Miete, denn um
>> Komponenten darzustellen, wird das Markup und die dort eingebetteten
>> ids benutzt. Man müsste das Verfahren umstellen, dass stattdessen der
>> Komponentenbaum dargestellt wird und dann hätte man ein komplett
>> andere Rahmenwerk, weil es dann nicht mehr (einfach) möglich ist,
>> Markup in Form von templates den Komponenten zuzuordnen.
>
> Das Problem ist doch, dass die Komponenten bei Wicket einmal in Java,
> und ein zweites mal in der Template zusammengestellt werden. Diese
> Redundanz stört mich. (Ganz abgesehen davon dass es bei den
> Anforderungen die ich habe so überhaupt nicht geht.)

Das kann ich aus Programmierer-Sicht nachvollziehen. Falls man jedoch
eine Aufgabenteilung betreiben möchte (die ich längst nicht für so
praxisrelevant halte wie es immer gesagt wird) wo es einen dummen
HTML-Designer gibt und einen Java-Entwickler, die jeweils nur ihre
eigene Syntax lesen können.

> Ich finde es ja garnicht schlecht, das HTML von Java zu trennen, aber
> das sollte doch auch komponentenweise gehen, nicht bloss seitenweise.
> Eine Seite kann man dann ja wieder als eine Komponente betrachten.

Das geht in Wicket, wenn man will. Dann expodieren einem aber die
HTML-Fragmente und außerdem hat man kein WYSIWYG mehr und kann keinen
entsprechenden Editor für das HTML benutzen.

Timo Stamm

unread,
Sep 14, 2005, 8:49:00 AM9/14/05
to
Stefan Matthias Aust wrote:
> Timo Stamm wrote:
>
>> Eine neue Sprache zu schreiben ist für mich weniger eine Option - für
>> produktiven Einsatz kommen für mich nur sehr wenige Sprachen in Frage,
>> da entscheide ich ausgesprochen konservativ.
>
>
> Meist sind derartige "produktive Lösungen" eh (technisch und
> konzeptuell) so langweilig, dass die gar keine interessante Sprache
> verdienen :)
>
> Will sagen: Mich faszinieren die Konzepte, aber ich will das gar nicht
> unbedingt in der Firma einsetzen müssen. Wenn ich da auch bezahlt
> werde, länger an einer konventionellen Lösung zu sitzen, habe ich kein
> größeres Problem damit.

Ich bin kein Angestellter und wenn ich an einer konventionellen Lösung
länger sitze als an einer kreativen hat das auch finanzielle Auswirkungen.

Trotzdem ist eine konventionelle Lösung einfach besser kalkulierbar und
deshalb nach meiner Erfahrung oft die bessere Entscheidung. Ich glaube
die Methodik von RoR (RoR wurde für ein komerzielles Produkt (basecamp)
entwickelt und ist gleichzeitig ein eigenständiges FrameWork) gelingt
nur selten - und sowieso nur wenn man sich mit der Thematik vorher gut
auseinandergesetzt hat.

Für die ganz speziellen Probleme einer Anwendung eine kreative Lösung zu
entwickeln lehne ich natürlich nicht ab - allerdings ist es aufgrund
mangelnden Weitblicks bisher immer schief gegangen wenn ich mich nicht
dazu gezwungen habe wirklich nur die speziellen Probleme zu lösen.


> Nur manchmal überkommt es mich, und ich würde
> ja schon gerne mit einer Sprache arbeiten, die auch Spass macht und
> nicht nur weit verbreitet, viele Bibliotheken und von einer IDE gut
> unterstützt ist.

Kann ich gut nachvollziehen. Momentan bietet mir Java aber noch genug
Möglichkeiten, (für mich) neues auszuprobieren.


>> Was nicht heissen soll dass ich es nicht absolut wichtig fände, sich
>> andere Sprachen anzuschauen. Da bin ich aber noch nicht mal mit Java
>> fertig. Ich programmiere erst seit ca. einem Jahr. Alles davor war
>> eher nicht zielgerichtete Spielerei.
>
>
> Okay, dann sprechen wir uns in 10 Jahren nochmal :) Dann wird auch dir
> Java langweilig geworden sein...

So lange wird's nicht dauern. Fürchte ich.

> Oder eben kein Java. Gerade für ein Template-System kann man schnell
> ein schickes Lisp o.ä. in ein Projekt einführen. Man sollte allerdings
> erstmal Terence Parrs Paper "Enforcing Strict Model-View Separation in
> Template Engines" lesen, um zu wissen, was man da warum tut.
>
> Als eine zentrale Aussage in seinem Paper empfinde ich übrigens die
> Eigenbeobachtung, dass er da fast soetwas wie eine funktionale Sprache
> baut.

Template Systeme sind für mich momentan uninteressant, weil es dafür
keine Anforderung gibt. Wenn es eine gibt, werde ich wiederum
konservativ entscheiden müssen und dann würde ich vermutlich TAL
benutzen, weil es mir der (kommerziell) interessanteste Ansatz zu sein
scheint.

Richtig ansprechend finde ich das Thema Templates aber eher nicht, es
gibt doch interessantere Gebiete für Experimente. Habe das Paper aber
auch noch nicht gelesen :)

>> Das Problem ist doch, dass die Komponenten bei Wicket einmal in Java,
>> und ein zweites mal in der Template zusammengestellt werden. Diese
>> Redundanz stört mich. (Ganz abgesehen davon dass es bei den
>> Anforderungen die ich habe so überhaupt nicht geht.)
>
>
> Das kann ich aus Programmierer-Sicht nachvollziehen. Falls man jedoch
> eine Aufgabenteilung betreiben möchte (die ich längst nicht für so
> praxisrelevant halte wie es immer gesagt wird) wo es einen dummen
> HTML-Designer gibt und einen Java-Entwickler, die jeweils nur ihre
> eigene Syntax lesen können.

Ich kann mich an eine Diskussion hier in der Gruppe erinnern, in der ich
die Wichtigkeit von der Trennung von HTML-Designer und Entwickler
vertreten habe.

Mittlerweile sehe ich das komplett anders, wie du schon sagst: längst
nicht so praxisrelevant wie immer behauptet.

Eigentlich spielt das doch nur bei Produkten eine Rolle, bei denen der
Kunde mit einem einfachen Template System arbeiten können muss - oder
vielleicht in grossen Firmen wo tatsächlich so eine Aufgabentrennung
besteht.


>> Ich finde es ja garnicht schlecht, das HTML von Java zu trennen, aber
>> das sollte doch auch komponentenweise gehen, nicht bloss seitenweise.
>> Eine Seite kann man dann ja wieder als eine Komponente betrachten.
>
>
> Das geht in Wicket, wenn man will.

Gut.


> Dann expodieren einem aber die
> HTML-Fragmente und außerdem hat man kein WYSIWYG mehr und kann keinen
> entsprechenden Editor für das HTML benutzen.

Damit habe ich überhaupt kein Problem. Die Entscheidung, Templates höher
zu werten als flexibilität beim Programmieren ist meiner Meinung nach
etwas an der Realität vorbei getroffen worden.

Lieber Komponentenorientierung als default und Seitenorientierung als
Spezialität als andersherum.

Timo

Timo Stamm

unread,
Sep 28, 2005, 5:14:15 PM9/28/05
to
Timo Stamm wrote:

[dynamische Formulare in den gängigen Web-Frameworks]

> Auch Wicket hat meines Wissens nichts dafür an Bord. Die normalen
> Formulare werden durch Beans (= statisch) definiert. Immerhin sehe ich
> Wicket als den besten Kandidaten, es in der Richtung zu erweitern.


Nachtrag zum Thema: Es ist kein Problem, mit Wicket dynamische Formulare
umzusetzen.

Ein Einstiegspunkt ist das BeanEditor Beispiel. Die interessanten Dinge
finden im BeanPanel [1] in den wicket-extensions statt. Für das
BeanPanel sollte man sich aber etwas Zeit nehmen, es erschliesst sich
nicht gerade alles auf den ersten Blick.

Ein einfacherer Ansatz ist, ein ListView mit Formularfeldern zu füllen.
Dabei muss man aber beachten, unbedingt optimizeItemRemoval auf true zu
setzen (steht mittlerweile auch in der API Dokumentation).

Mit Border und Panel kann man für dynamische Komponenten jeweils eine
eigene HTML-Datei benutzt. Es ist dann nicht nötig, in der HTML-Datei
einer Seite den Markup der Komponente einzufügen.


In Sonderfällen ist es auch möglich, komplett auf die HTML-Dateien zu
verzichten und mit Java den Markup zu konstruieren. Zum Beispiel lässt
sich in Component#onRender in die Response schreiben, und dabei kann man
auch andere Komponenten rendern. In Component#onComponentTagBody lässt
sich der MarkupStream auch beeinflussen.


Timo


[1]
http://cvs.sourceforge.net/viewcvs.py/wicket/wicket-extensions/src/java/wicket/extensions/markup/html/beanedit/BeanPanel.java?rev=1.6&view=auto

0 new messages