Heiner Kücker

JSP WorkFlow Engine Control and Command

Home

Java-Seite

   ASM Improved

   heterogene
   Map, HMap

   Constraint
   Code Generator

   JSP WorkFlow
   PageFlow FlowControl
   Page Flow Engine
   Web Flow Engine
   Control_and_Command

   JSP_Spreadsheet

   Code-Generator
   für Option-Either-Stil
   in Java

   verbesserter
   Comparator

   Fluent-Interface
   Code-Generator
   auf Basis
   einer Grammatik

   Visitor mit Multidispatch

   for-Schleife mit
   yield-return

   Kognitions-Maschine
   semantisches Netz

   Domain Parser

   Codegenerator_für
   hierarchische
   Datenstrukturen

   Expression_Engine
   Formula_Parser

   Thread Preprocessor

   State Transition Engine

   AspectJ

   Java_Explorer

   DBF_Library

   Kalender_Applet

   SetGetGen

   BeanSetGet

   CheckPackage

   LineNumbers

   GradDms

   Excel-Export

   StringTokenizer

   JspDoc

   JspCheck

   JSP-Schulung
   Java Server Pages
   Struts

   Ascii-Tabellen-
   Layouter

   Ascii-Baum-
   Layouter

   Ascii-Art-Fluss-
   Diagramm-
   Parser

   AsciiArt
   AssignmentMatrix
   Layouter

   StringSerial

   Silbentrennung

   JDBC_Schlüssel-
   Generierung

   bidirektional/
   unidirektional
   gelinkte Liste

   Java_Sitemap
   Generator

   XmlBuilder

   RangeMap

   StringFormatter

   VersionSafe
   XCopy

   JTextField

   CommandLine-
   ParamReader

   Bitmap-Grafik

   MultiMarkable-
   Buffered-
   InputStream

   JavaCache

   JdomUtil

   CollectionUtil

   XML Really
   Pull Parser

   Log-Filter

   Remote-Protokoll

   Sudoku-Generator

   Delegation statt
   Mehrfachvererbung

   Disjunct
   Interval Set

   WebCam_Demo

   Weiterentwicklung_Java

Alaska-XBase++-Seite

Projekte

Philosophien
Techniken


Konzepte

Sudoku

Kontakt /
Impressum


Links

SiteMap





Letzte Aktualisierung:
14.05.2005
Control and Command

Fluss-Steuerung (WebFlow) für JSP-Anwendungen

Demo-Applikation auf www.control-and-command.de

Veröffentlicht im Java-Magazin 03.2003, Seite 81 - 88, (web apps Fluss-Steuerung für JSP-Anwendungen)

News-Update Java-Magazin 03. Dezember 2004

Das Framework Control and Command ist eine Fluss-Steuerung für JSP- und Servlet-Applikationen.
Es beruht auf einer Java/C-ähnlichen Steuersprache und besitzt Strukturen (Schleifen, Verzweigungen),
Befehle, Unterprogramme (Prozeduren, Funktionen),
lokale Variable und Parameter (per value/reference).
The Framework Control and Command is an JSP FlowControl Workflow PageFlow Engine for
JSP (Java Server pages) and Servlet-Applications.
It's based on a own Scriptlanguage and has Struktures, Instructions, Subprogramms,
lokal Variabels and Parameters (per value or per reference).
The Compiler and the Runtimeenvironment for the Flow Language is completely written in Java.
The page flow and additional features are completely written in the script langauge.

Es vollzieht die Entwicklung der EDV von der GOTO-Programmierung zur strukturierten Programmierung
für JSP-Applikationen nach (Synergie-Ansatz). Dabei entspricht die konventionelle Herangehensweise
mit forward() und redirect() dem GOTO-Ansatz. Das Action-Mapping analog Struts und anderer Web-
Frameworks nach dem Prinzip eines endlichen Zustandsautomaten (Finite State Machine) ist
demgegenüber wesentlich unübersichtlicher und bietet weniger Möglichkeiten.

Das Wiederaufnehmen des Flusses nach dem Absenden des erzeugten HTML und dem erneuten Request des
Browsers habe ich unter das API des CnC-Frameworks gedrückt.

Dadurch ist das Hinnehmen (Resignieren vor) einer ereignisorientierten Realisierung, die durch das
Postulieren des MVC-Patterns zur Lösung erhoben wird, nicht mehr notwendig.

Web-Applikationen können wie modale Terminal- oder DOS-Applikationen geschrieben werden.

Auf dieser Basis könnte MVC (Ereignisorientierung) auf einer nächsthöheren Ebene eine Rolle spielen,
wenn die Browser Möglichkeiten zur Realisierung richtiger GUI-Applikationen durch das Aktualisieren
von Feldinhalten, Tabellenzellen und Menüs, Absenden von Button- und Change-Ereignissen und allen
weiteren GUI-Notwendigkeiten (Callback-Hooks, Remote-Referenzen) zusätzlich zum kompletten Neuaufbau
einer HTML-Seite böten.

Ausgehend von den bekannten Prinzipien der strukturierten Programmierung, wie Schleifen,
Verzweigungen und Unterprogramme, ist die Realisierung als Compiler mit einer dynamisch erzeugten
internen Befehlstabelle relativ naheliegend.

Aktuell sind ähnliche Frameworks, teilweise in anderen Programmiersprachen wie Smalltalk (SeaSide),
als Continuation-Servers bekannt. Dabei benutzt CnC keine nativen Continuations in Java, sondern
eine eigene Script-Sprache.

Ein Programm könnte folgendermassen aussehen:

procedure daterange()
  while ( true ) // Endlos-Schleife
  {
    session:CNC_MESSAGE_KEY := "Bitte Datum von 1.1.2005 bis 31.12.2005 eingeben";
    jsp ( "/date/date.jsp" ); // hier bleibt der Fluss stehen, bis ein Request vom Browser zurückkommt
    session:date := strToDate( request:date ) ; // eingegebenes Datum zwischenspeichern
    if ( session:date >= strToDate( "1.1.2005" ) ) // if date >= 01.01.2005
    {
      if ( session:date <= strToDate( "31.12.2005" ) ) // if date <= 31.12.2005
      {
        session:CNC_MESSAGE_KEY := "Datum ist korrekt" ; // Setzen Meldung
        break ; // Schleife beenden
      } // end if
    } // end if
  } // end while
} // end procedure daterange


Architektur CnC
===============

Kompilieren:
------------

     Steuerdatei
      flow.cnc
         |
   wird gelesen von
         |
  FlowControlParser
         |
      erzeugt
         |
   FlowControlTable ---- enthält ---- > FlowControlInstruction


Ablauf:
-------

    +------- > FlowControl --- benutzt --- > FlowControlTable --- enthält --- > FlowControlInstruction
    |           |     |
    |        startet ruft
    |           |     |
    |          JSP    +--- > ActionMethoden (z.B. CncDemoDefaultActions)
    |           |
    |         ruft (Browser HTTP-Request)
    |           |
    |       CncServlet --- erweitert durch --- > Applikations-Servlet (z.B. CncDemoServlet)
    |           |
    |  übergibt die Steuerung an
    |           |
    +-----------+

Demo-Applikation auf www.control-and-command.de



WAR-File für Tomcat5 unter JDK 1.4

Download cncdemo.war

Das war-File können Sie in das Verzeichnis TOMCAT_HOME/webapps kopieren.

Tomcat (re)starten.

Ansehen mit http://localhost:8080/cncdemo .



Source-Code

Download der Quelldateien Cnc.zip

Installation:

Entpacken in Verzeichnis Ihrer Wahl (z.B. C:\CnC)

Kompilieren mit ANT (build.bat oder build.xml)

Start im Tomcat 5 mit http://localhost:8080/cncdemo


Syntax Steuer Datei für UltraEdit

Zum angenehmen Editieren der Steuerdatei flow.cnc habe ich für den UltraEdit
(mein bevorzugter Editor neben der Eclipse, hat einen super Spaltenmodus) eine
Sequenz für die Wortlistendatei (standardmäßig "WORDFILE.TXT") erstellt.

Sie müssen die Sequenz in die Wortlistendatei (standardmäßig "WORDFILE.TXT") Ihrer
UltraEdit-Installation einfügen.

Wichtig ist dabei, dass die Nummer in der ersten Zeile (L11) die exakte laufende
Nummer in der Reihenfolge der Syntax-Definitionen angibt.

Download der Syntax Steuer Datei WORDFILE.TXT für UltraEdit.


Anleitung Control and Command
=============================

Unterstützung
-------------

Vielen Dank an die im folgenden aufgeführten Privatpersonen,
durch deren Unterstützung CnC entstehen konnte:

Ingo Ciechowski (CIS-Computer GmbH)
Ralf Schramm (Deutsche Bahn AG)
Suresh David Tucker (Deutsche Bahn AG)

Allgemeines
-----------

Control and Command ist eine Lösung zur Ablaufsteuerung von Web-
Applikationen.

Herkömmliche JSP-Servlet-Applikationen realisieren ihren
Steuerfluss in forwards, form-actions und link-hrefs in einer Art
GOTO-Programmierung.

Besser ist die Vorgehensweise von Struts mit einer zentralen
Steuerdatei struts-config.xml mit dem zentralen Hinterlegen der
Navigation als Mapping-Tabelle im Tag action.

Dieses Action-Mapping ist aber noch relativ unübersichtlich.

In langen Spaziergängen habe ich die Idee für mein CnC entwickelt
(zugegeben, kein besonders phantsievoller Name, Liquid oder so
wäre vielleicht besser, ich weiss aber nicht wie es mit dem
Markenschutz ist).

Da das HTTP-Protokoll statuslos ist, muss der Status irgendwo
zwischengespeichert werden.

Ich habe überlegt, dass ein Prozessor (in Rückbesinnung an meine
Z80- und 8086- Assemblerzeit) als Status nur seinen Program-
Counter und seine Register hat. Diese relativ geringe
Informationsmenge könnte man zum Browser und von dort aus wieder
zurücksenden (Hidden-Fields, URL-Encoding). Die Session enthält
in diesem Falle die Informationen analog dem Hauptspeicher.

Der Steuerfluss wird komplett in CnC-Language aufgeschrieben und
die JSPs sowie Actions returnen lediglich zur zentralen
Steuerkomponente. Die Steuerkomponente entscheidet, welche JSP
oder Action als nächstes aufgerufen wird.

Mit CnC ist es möglich, eine JSP-Servlet-Applikation wie eine
modale Terminal(DOS)-Applikation zu schreiben.

-alter Zustand
   Im JSP (Link oder Form-Action) und im Servlet (forward)
   selbst ist das Sprungziel gespeichert.

   Sehr unflexibel und schlecht zu warten.

-Jakarta-Struts
   Mapping symbolische Namen für Actions
   Actions können unter unterschiedlichen logischen Namen
   und mit differierenden Sprungzielen deployt werden.
   keine logischen Namen für Views (JSP).
   wesentlich besser

-Problem
   Nutzung eines JSP zum Editieren oder Hinzufügen DB-Record

   edit-Button --> getRecord --+            +--> UPDATE
                               |   +-----+  |
                               +-->| JSP |--+
                               |   +-----+  |
   add -Button --> initForm ---+            +--> INSERT

Hilfskonstrukte über request-Parameter oder implizite Annahmen
(wenn Record-ID leer, dann INSERT).
Struts hilft hier nicht.

-Basis der Idee
   Synergie

-Zurück zu Wurzeln
   -wie funktioniert ein Prozessor

      PC-Programmcounter
      Register
      Flags
      RAM

   -Programmabarbeitung ab Reset
      ein Befehl ADD muss auch nicht wissen, wohin er
      zurück-/weiter-springen muss

-mein Konzept Control and Command

                 +------+
                 | Menu |<------------------+
                 +------+                   |
                   |  |                     |
    +--------------+  +------+              |
    |                        |              |
 +--------+               +------+          |
 |ListView|<--+           | Form |          |
 +--------+   |           +------+          |
   |          |              |              |
   +-->Top----+           +------+          |
   |          |           |Action|          |
   +-->PgUp---+           +------+          |
   |          |              |              |
   +-->PgDn---+              +--------------+
   |          |
   +-->Bott---+




    +----------------+             Commands
    | Control        |             +-------+
    |                |------------>|  JSP  |
    |                |             +-------+
    |                |                 |
    |                |<----------------+
    |                |
    |                |             +--------------+
    |                |------------>|Backend-Action|
    |                |             +--------------+
    |                |                 |
    |                |<----------------+
    |                |
    |                |
    |                |
    |                |
    +----------------+


                                Command-Table
                                (applikationsweites Singleton)
                                   +--------+------------------------------+
                                   |Adress  | Command-Name                 |
                                   +--------+------------------------------+
                                   |      0 | menu.jsp                     |
                                   +--------+------------------------------+
                           +------>|      1 | Goto IF <xxx> 5              |
                           |       +--------+------------------------------+
                           |       |      2 | Goto IF <xxx> xx             |
                           |       +--------+------------------------------+
                           |       |      3 | Goto IF <xxx> xx             |
                           |       +--------+------------------------------+
                           |       |      4 | Goto 0                       |
                           |       +--------+------------------------------+
  +-----------------+      |       |      5 | ListeGetAction               |
  | Program-Counter |------+       +--------+------------------------------+
  +-----------------+              |      6 | listview.jsp                 |
   Programm-Counter wird           +--------+------------------------------+
   in Session abgespeichert        |      7 | Goto IF <Up-Button>  13      |
   (später sehen wir, daß es       +--------+------------------------------+
    damit ein Problem gibt)        |      8 | Goto IF <Dn-Button>  15      |
                                   +--------+------------------------------+
                                   |      9 | Goto IF <Edit-Button> 17     |
                                   +--------+------------------------------+
                                   |     10 | Goto IF <Add-Button>         |
                                   +--------+------------------------------+
                                   |     11 | Goto IF <Del-Button>         |
                                   +--------+------------------------------+
                                   |     12 | Goto IF <Ret-Button> 0       |
                                   +--------+------------------------------+
                                   |     13 | PageUpAction                 |
                                   +--------+------------------------------+
                                   |     14 | Goto 6                       |
                                   +--------+------------------------------+
                                   |     15 | PageDnAction                 |
                                   +--------+------------------------------+
                                   |     16 | Goto 6                       |
                                   +--------+------------------------------+
                                   |     17 | RecordGetAction              |
                                   +--------+------------------------------+
                                   |     18 | formedit.jsp                 |
                                   +--------+------------------------------+
                                   |     19 | Goto IF <Break-Button> 6     |
                                   +--------+------------------------------+
                                   |     20 | RecordSaveAction             |
                                   +--------+------------------------------+
                                   |     21 | Goto 6                       |
                                   +--------+------------------------------+
                                   |     22 |                              |
                                   +--------+------------------------------+
                                   |     .. | und so weiter                |
                                   +--------+------------------------------+


    +----------------+                                  Commands
    | Control        |    Parameter(z.B. add/edit)      +-------+
    |                |--------------------------------->|  JSP  |
    |                |                                  +-------+
    |                |                                      |
    |                |<-------------------------------------+
    |                |     Ergebnis-Flags
    |                |
    |                |
    |                |     Parameter (z.B. SELECT-Cond) +--------------+
    |                |--------------------------------->|Backend-Action|
    |                |                                  +--------------+
    |                |                                      |
    |                |<-------------------------------------+
    |                |     Ergebnis-Flags
    |                |
    +----------------+


Der virtuelle Prozessor sollte Register besitzen. Dadurch ist die
Codierung von Flags in Registern und das Halten komplexerer als
nur binärer Stati möglich.

   Wegfall Flags
   binäre Codierung
   Flag1 = 1
   Flag2 = 2
   Flag3 = 4

   State = Flag2 + Flag3

   +-+-+-+-+-+-+-+-+-+
   |0|0|0|0|0|0|1|1|0|
   +-+-+-+-+-+-+-+-+-+
                | | |
                | | +------ Flag1
                | +-------- Flag2
                +---------- Flag3

Was sollte die Control-Komponente können:

Goto-Programmierung vs. strukturierte Prog

Formulierung der Steuerstruktur
   -like 4GL
   -XML
   -graf. Flussdiagramm-Tool (Visio)
   -Graf. Tool zur strukturierten Prog

Unterprogramme
   Parameterpassing (per value, per reference)
   lokale variablen (compile-time-scope, runt-time-scope)

Problem stateless
   Analogie zu Win-Programm

Problem Back-Button und Strg-N
   Status (Flags und register) in Page(Session) speichern

Verschlüsselung Status (Synchronisations-Token)

Komponenten
   Parser für Control und Erzeugung Control-Table
   Control-Servlet

Das Framework CnC spielt die Rolle einer zentralen Fluss-Steuer-
Komponente, die von einer Steuersprache, ähnlich einem primitiven
Basic, gespeist wird.


Aufbau einer CnC-Applkation
---------------------------

Schreiben des Flusses in flow.cnc (Name lässt sich
umkonfigurieren)

Eigenes zentrales Servlet vom CncServlet ableiten (analog zu
CncDemoServlet) (Eintragen in web.xml)

Erstellen der Action-Methoden (Controller) in entsprechenden
Action-Klassen

Schreiben Ihrer JSP´s (Views).

Erstellen eigener Tags oder Benutzen verfügbarer Tag-Libs.

Datenbank-Anbindung (nicht durch CnC unterstützt).


Konfigurationsdatei web.xml
---------------------------

CnC-Servlet:

Hier tragen sie das zentrale Servlet ihrer Web-Applikation ein,
das sie von de.cnc.CncServlet abgeleitet haben.

  <servlet>
    <servlet-name>cncaction</servlet-name>
    <servlet-class>de.cnc.CncDemoServlet</servlet-class>
    <init-param>
     ... hier folgen weitere Initialsierungsparameter


Url-Pattern
    Eintrag in web.xml
    Konstante in cnc-servlet

Das URL-Pattern *.cnc ist auf obiges Servlet cncaction gemappt,
wodurch alle URIs, die mit .cnc enden, auf das zentrale Servlet
umgeleitet werden.

  <servlet-mapping>
    <servlet-name>cncaction</servlet-name>
    <url-pattern>*.cnc</url-pattern>
  </servlet-mapping>

Steuerdatei flow.cnc
--------------------

Der Steuerfluss wird in einer Script-Datei mit dem Default-Namen
flow.cnc codiert. In der Konfigurationsdatei der Web-Applikation
web.xml kann ein alternativer Name festgelegt werden:

    <init-param>
      <param-name>flowfile</param-name>
      <param-value>flow.cnc</param-value>
    </init-param>

Der alternative Name wird in der init-Methode der Klasse
FlowControl gelesen.

Der Pfad ergibt sich aus dem WEB-INF Verzeichniss der
Webapplikation:

    /WEB-INF/dateiname.cnc

Flow-Control-Mode
-----------------

Für die Fluss-Steuerung gibt es zwei Möglichkeiten, Browser-
Leading oder Session-Leading.

Beim Browser-Leading wird der Status des FlowStack zum Browser
gesendet und von ihm wieder zu Server gesendet. Das Benutzen des
Back-Buttons oder des Öffnen eines neuen Browser-Fensters ist
erlaubt. Der vom Browser gesendete Status bestimmt den Fluss-
Status.

Beim Session-Leading wird lediglich eine Prüfummer zum Browser
gesendet, beim Auftreten einer invaliden Prüfnummer wird der
aktuelle Fluss abgebrochen und mit einer Fehlermeldung zur
Adresse 0 gesprungen. Ein Mechanismus zum Informieren der
Applikation, dass ein CnC-Status-corrupt-Event aufgetreten ist,
wird noch eingebaut.

Die Betriebsart kann über die Methoden

    FlowControl#setBrowserLeading()
    FlowControl#getBrowserLeading()

gesetzt und abgefragt werden.
Alternativ ist die Einstellung in web.xml möglich:

    <init-param>
      <param-name>flowleading</param-name>
      <param-value>browser(default) oder session</param-value>
    </init-param>


Problem mit der Form
--------------------

Links können bestimmte URIs ansteuern. Paramter können mit dem
Anhängen eines Strings "?name=value" an die URI mitgegeben
werden. Dabei werden keine Formulardaten mit übertragen.

Forms können nur eine URI ansprechen. Parameter können über
Hidden-Fields mitgegeben werden.

Welcher Button innerhalb der Form gedrückt wurde, muss über die
Request-Parameter ermittelt werden. Dabei muß nach HTML-Buttons
und Image-Buttons unterschieden werden. Dabei werden die in der
submitteten Form (pro HTML-Seite sind mehrere möglich)
enthaltenen Formulardaten mit übertragen.

<form action="ControlServlet?controlstatus=003" method="post">

                    Eine Form ist notwendig um Formulardaten an den Server senden zu können.
                    Eine Form kann nur eine einzige Action ansteuern, egal welcher Submit-Button gedrückt wird.
                    Der Action-URI können weitere Parameter angehängt werden.

  <input type="text" value="initialwert" size="100">

                    Ein Formularfeld muß den Anfangswert (value="...") aus der Formularbean bekommen.
                    Über den Namen kann das ControlServlet den eingegeben Wert in die Formularbean einparsen.

  <input type="submit" name="name" value="value">

                    Beim Betätigen des Submit-Button´s wird die Action-URI der Form angesteuert.
                    Unterschiedliche Submit-Button´s können über Name und Value differenziert werden.
                    Der Value ist dabei der Text auf dem Button (Aufpassen bei landesspezifischer Anpassung).

  <input type="image" name="Button" src="Abbrechen.gif" alt="Abbrechen">
                    Gif-Buttons wirken wie Submit-Buttons und erlauben auch Differenzierung über Name und Value
                    Der Name wird als name.x und name.y im Request abgelegt,
                    weshalb über alle Parameter-Namen im Request mit String.startsWith() nach dem Namen gesucht
                    werden muß.

  <input type="button"
                    JavaScript-Button noch nacharbeiten

  <a href="ControlServlet?controlstatus=003&action=MAINMENU">Zurück zum Hauptmenü</a>
                    Beim Betätigen eines Links in der Form werden die Formularwerte nicht in den request mitgeliefert.
                    Der Link-URI können weitere Parameter angehängt werden.

</form>


GOTO-Actions
------------

In Web-Applikationen werden oft Navigationsleisten verwendet.
Diese ermöglichen das Aufrufen bestimmter Seiten unabhängig vom
aktuellen Status der Web-Applikation. Laufende Vorgänge werden
abgebrochen und zur Zielseite verzweigt.

Damit solche globalen Links nicht an allen Stellen im Fluss von
CnC (flow.cnc) codiert werden müssen, gibt es GOTO-Actions.

GOTO-Actions werden in der excute-Methode der Klasse FlowControl
ausgewertet. Dabei können Labels (Sprung-Marken) oder Prozeduren
angesprungen werden.

Das direkte Ansteuern von Prozeduren ist erlaubt, weil in einer
Prozedur ein Teilbereich der Web-Applikation codiert sein kann.

Beim Return aus diesen Prozeduren ist der Stack nicht mehr
korrekt. Deshalb wird bei Return auf leeren Stack zur Adresse 0 (
erste Zeile in der Prozedur main) verzweigt. Hier sollte die
Hauptseite (evtl. nach Login liegende Hauptseite) der Web-
Applikation liegen.

GOTO-Actions werden in Links und bei Buttons mit dem Prefix
cnc_goto_ (hinterlegt in de.cnc.RequestKeys) gekennzeichnet.

Damit es auch mit Image-Buttons funktioniert, werden angehängte
".x" und ".y" entfernt.

Für die GOTO-Actions gibt es die CnC-Tags

  <cnc:hrefgoto
  <cnc:buttongoto
  <cnc:imagebuttongoto

Verwendung von Custom-JSP-Tags
------------------------------

Zum Encoden des CnC-Status und des Session-Key für Links und
Forms stehen spezielle Customer-Defined-Tags zur Verfügung.

Um die Tags zu verwenden, muss in der jeweiligen JSP-Seite
folgende JSP-Direktive stehen:

<%@ taglib uri="/WEB-INF/cnc.tld" prefix="cnc" %>

Links:

Zum Encoding von Links steht das Href-Tag zur Verfügung.

<cnc:href href="action"/>Link-Text</a>

Forms:

<cnc:form action="action"/>
 ...
 ...
</form>


Debugging:

Das Debug-Tag gibt einen vorformatierten Text (siehe <pre>-Tag) mit
den Zeilen aus der Fluss-Steuer-Datei flow.cnc aus. Die aktuelle
Zeile wird hevorgehoben dargestellt.

<cnc:debug/>


Blättern:

Zum Blättern stehen die Tags:
  <cnc:buttonfirstpage/>
  <cnc:buttonprevpage/>
  <cnc:buttonnextpage/>
  <cnc:buttonlastpage/>

zur Verfügung. Weitere Tags für Blätter-Links und Blätter-Image-
Buttons folgen noch. Die von diesen Tags abgesendeten Actions
bzw. Request-Parameter werden im CncServlet als implizite Actions
abgearbeitet und anschliessend zur Source-JSP zurückgekehrt. Zur
Verwendung dieser Tags muss man lediglich vorher auf dem Session-
Key CNC_LIST_KEY eine ArrayList ablegen.

Weitere implizite Actions für MvUp, MvDn, Insert, Delete und Add
für Listen baue ich noch ein.

Implizite Actions
-----------------

noch nicht fertig

Input-Tags für Bean-Properties die keine Strings sind
-----------------------------------------------------

Der Browser liefert alle Daten aus den HTML-Forms als Strings. In
der Klasse de.cnc.util.BeanUtil Methode convertToClass erfolgt
die Umwandlung der Strings aus dem Browser-Request in die
gewünschte Zielklasse der Bean-Property. Hier ist der Ansatzpunkt
zum Einarbeiten zusätzlicher Klassen und für die
Internationalisierung (I18N).

Unterdücken des Einparsens von Formular-Daten beim Betätigen des Abbrechen-Buttons
----------------------------------------------------------------------------------

Durch Mitsenden eines Request-Keys CNC_BUTTON_NO_PARSE ("cnc_buton_no_parse") kann das
Einparsen in die Formular-Bean (Session-Key CNC_FORM_KEY) und Listen-Bean
(Session-Key CNC_LIST_KEY) vermieden werden.

<input type="submit" name="<%= de.cnc.RequestKeys.CNC_NO_PARSE %>" value="Abbruch"/>
oder
<cnc:formbreakbutton value="Abbruch"/>

Der Vorteil dieser Option ist, dass für die Funktionalität "Abbrechen" kein
extra Puffer für die Originalwerte (Editierpuffer) bereitgehalten werden muss.
Die veränderten Werte werden beim Abbruch nicht eingeparst und können die
Originalwerte nicht überschreiben.

Implizite Session-Values
------------------------

Implizite Session-Values sind Schlüssel-Werte-Paare aus dem Request, die
automatisch wieder in die entsprechenden Session-Keys zurückgeschrieben werden.

Dadurch ist es nicht nötig, diese Werte mit

    session:setAttribute( request.getAttribute(...) )

oder mit einer Zuweisung in die Session zurückzuschreiben.

Sie haben den Festen Prefix

    RequestKeys.CNC_SESSION_VALUE_PREFIX.

Im <cnc:input>-Tag (JSP) wird der Prefix bei aktiviertem Attribut
sessionvalue="true" vor den Namen gesetzt. Dieser Prefix wird beim
Einparsen im CncServlet abgeschnitten.

Die Adressräume der CnC-Sprache
-------------------------------

Die CnC-Steuersprache unterstützt die Scopes der JSP-Servlet-Spezifikation
request, session und application über entsprechende Prefixe der Variablen-Namen.

Die Key´s der jeweiligen Map´s der JSP-Servlet-Applikation sind die
Variablennamen der CnC-Sprache.

        CnC-Language                |                          Java
------------------------------------+-----------------------------------------------
request:param:Xyz (nur lesend)      | request.getParameter( "Xyz" );
                                    |
request:attr:Xyz                    | request.getAttribute( "Xyz" );
request:attr:Xyz := <expr>          | request.setAttribute( "Xyz" , <expr> );
                                    |
session:Xyz                         | session.getAttribute( "Xyz" );
session:Xyz := <expr>               | session.setAttribute( "Xyz" , <expr> );
                                    |
application:attr:Xyz                | application.getAttribute( "Xyz" );
application:attr:Xyz := <expr>      | application.setAttribute( "Xyz" , <expr> );
                                    |
application:init:Xyz (nur lesend)   | application.getInitParameter( "Xyz" );
                                    |

implizite Variable
------------------

cnc_button        - der Name des betätigten Buttons
cnc_button_index  - der Index des Buttons in Tabellen (in einfachen Forms -1)
cnc_link          - Abfrage action="..." der HTML-FORM oder Link HREF="..."
cnc_javascript_on - Abfrage, ob JavaScript eingeschaltet ist noch nicht fertig)
cnc_no_validate   - Abfrage, ob ein Button mit der Option validate=false" betätigt wurde

Ausdrücke in der CnC-Language
-----------------------------

Alle Bedingungen, Abfragen und Zuweisungen in den CnC-Statements werden durch
meine Expression-Library realisiert. Sie erlaubt das Arbeiten mit den java.lang-
Elementar-Typen, die üblichen Verküpfungs- und Zuweisungsoperatoren, Methoden-
Aufruf per Reflection, Operationen mit Array´s, java.util.List und
java.util.Map, Sequencen und einiges mehr. Für Zuweisungen benutze ich := statt
einem einfachen = . Hat mir eben so besser gefallen. Zur Anwendung bitte die
entsprechende WebSite und Online-Demo ansehen.

Befehle für die Steuerdatei flow.cnc (CnC-Language)
===================================================

Auflistung aller erlaubten Deklarationen und Befehle für flow.cnc
-----------------------------------------------------------------

action ( <String-Expression mit dem Namen der Action> ); // Aufruf einer Action-Methode
action ( "ActionClass#ActionMethod" ); // Action-Klasse und Action-Methode durch '#' (Hyphen) getrennt
session:a := action( ... ); // Zuweisung des Rückgabewertes einer Action zu einer Variable (session:xxx oder application:xxx)

break;

call ( <String-Expression mit dem Namen der Procedure/Function> );
session:a := call ( <String-Expression mit dem Namen der Function> ); // Zuweisung des Rückgabewertes einer Function zu einer Variable
                                                                      // (session:xxx oder application:xxx)

continue; // zum Anfang einer do oder while-Schleife springen

do ( <bedingung, boolean-Expression> ) { <body> } // Schleife wird mindestens einmal durchlaufen und sonst solange Bedingung == true

else  { <body> } // die geschwungenen Klammern sind zwingend erfoderlich

else if ( <bedingung, boolean-Expression> ) { <body> } // die geschwungenen Klammern sind zwingend erfoderlich

function <procedure_name> ( <parameter> ) { <body> } // Function-Deklaration

goto <label_bezeichner>; // Ansprung eines Labels in der main-Procedur zum Realisieren von Navigationslinks

if ( <bedingung, boolean-Expression> ) { <body> } // die geschwungenen Klammern sind zwingend erfoderlich

invalidate; // Session-Invalidate

jsp ( <String-Expression mit dem Namen der JSP> ); // Anzeigen einer JSP, der Fluss stoppt hier und kann durch die CnC-Mechanismen
                                                   // (Action-Mapping in web.xml *.cnc auf zentrales Servlet,
                                                   // Wiederaufnehmen des Flusses aus URL-Encoding oder Hidden-Field bzw. Session)
                                                   // beim nächsten Browser-Request beim nachfolgenden Befehl
                                                   // wieder aufgenommen werden

label <label_bezeichner>; // ein anspringbares Label zur Realisierung von Navigationslinks, nur in der main-procedure erlaubt

local session:<varname>; // nur in der aktuellen procedure/function und in von dieser aufgerufenen procedures/functions gültige Variable

logon { <body> } // Bereich, in dem keine Prüfung auf Berechtigung erfolgt, damit ein Einlogggen überhaupt möglich ist, nur in der main-procedure erlaubt

procedure <procedure_name> ( <parameter> ) { <body> } // Procedure-Deklaration

reset ( <String-Expression mit variablen_name> ); // Löschen einer Variable (session:xxx oder application:xxx), die Klammern sind zwingend erforderlich

return; // Rückkehr aus Procedure
return ( <return_expression> ); // Rückkehr aus Function

while  ( <bedingung, boolean-Expression> ) { <body> } // Schleife wird durchlaufen solange Bedingung == true, die geschwungenen Klammern sind zwingend erfoderlich

Kommentare
----------

Wie in Java sind Inline-Kommentare mit doppeltem Schrägstrich

....; // Kommentar

oder Bracketkommentare

/* Kommentar, auch mehrzeilig */

möglich.

Deklaration procedure
---------------------

Die Deklaration einer procedure schließt ein Unterprogramm ohne Rückgabewert
oder das Hauptprogramm main ein. In der Steuerdatei flow.cnc muss mindestens das
Hauptprogramm main deklariert sein.

 procedure main ()
 {
  ...
 } // end procedure main

Bei Verwendung von Prozeduren (ausser main) muss die flowleading-Methode auf
session stehen, sonst gibt es einen Runtime-Error. Dies hat seinen Grund darin,
dass nicht der gesamte Stack, dieser kann sehr gross werden, zum Browser und von
dort wieder zum Server gesendet werden soll.

Lokale Variablen werden mit local (siehe dort) festgelegt.

Ein Unterprogramm kann mit

    return;

oder

    goto sprungziel;

beendet werden.

Achtung, beim Verlassen über goto werden lokale Variable und Referenz-Parameter
nicht zurückgeschrieben. Der Stack der Applikation wird verworfen.

Ausserdem kehrt der Steuerfluss beim Erreichen des Prozedur-Endes,
das heisst der schliessenden geschwungenen Klammer

      ...
    } // end procedure

zur aufrufenden Prozedur/Function zurück.

Beim Aufruf über call können Parameter übergeben werden.

    call procName ( session:FORM_KEY )

Es sind beliebig viele Parameter erlaubt.
Über das Attribute refParam kann die Variable per Referenz übergeben werden.

Dabei werden die Parameter per value (Übergabe des Wertes ohne Rückwirkungen auf
die aufrufende Procedure/Function) übergeben.

Alternativ können die Parameter auch per reference (Zurückkopieren der in der
aufgerufenen Procedure/Function aufgetretenen Änderungen in die aufrufende
Procedure/Function)

    call procName ( refparam session:FORM_KEY )

Funktionsweise:

Beim Start der procedure wird eine lokale Variable mit dem param-Namen aus dem
procedure-Statement gebildet und der Wert aus dem call-Statement auf diese
lokale Variable kopiert.

Wenn der Parameter per Referenz (Schlüselwort refparam) übergeben wurde, wird
beim Beenden der Procedure das Objekt vom inneren Variablen-Key (param-Name in
der procedure-eklaration) zum äusseren Variablen-Key (param-Name im call-
Statement) zurückkopiert.


Deklaration function
--------------------

Die Deklararation function schließt ein Unterprogramm mit einem Rückgabewert ein.

 function artikelLookUp ()
 {
  ...
 } // end function artikelLookUp

Bei Verwendung von Funktionen muss die flowleading-Methode auf session stehen,
sonst gibt es einen Runtime-Error. Dies hat seinen Grund darin, dass nicht der
gesamte Stack, dieser kann sehr gross werden, zum Browser und von dort wieder
zum Server gesendet werden soll.

Lokale Variablen werden mit local (siehe dort) festgelegt.

Eine Function kann mit
    return ( <return_expression> );

oder

    goto sprungziel;

beendet werden.

Achtung, beim Verlassen über goto werden lokale Variable und Referenz-Parameter
nicht zurückgeschrieben.

Ausserdem kehrt der Steuerfluss beim Erreichen des Prozedur-Endes

      ...
    } // end function


zur aufrufenden Prozedur/Function zurück.

Der Rückgabewert der Function kann einer Variable zugewiesen werden:

    session:retVal := call funcName ()

Andererseits kann der Rückgabewert aber auch verworfen werden:

    call funcName()

Die Verwendung eines Function-Call in einem Ausdruck ist nicht möglich,
da die Expression-Engine getrennt von der Flow-Engine arbeitet und
die Flow-Engine im Gegensatz zur Expression-Engine das Unterbrechen und
Wiederaufnehmen des Flusses beim jsp-Befehl realisiert.

Beim Aufruf über call können Parameter übergeben werden.

    session:retVal := call funcName ( session:FORM_KEY )

Es sind beliebig viele Parameter erlaubt.
Über das Attribute refParam kann die Variable per Referenz übergeben werden.

Dabei werden die Parameter per value (Übergabe des Wertes ohne Rückwirkungen auf
die aufrufende Procedure/Function) übergeben.

Alternativ können die Parameter auch per reference (Zurückkopieren der in der
aufgerufenen Procedure/Function aufgetretenen Änderungen in die aufrufende
Procedure/Function)

    session:retVal := call funcName ( refparam session:FORM_KEY )

Funktionsweise:

Beim Start der procedure wird eine lokale Variable mit dem param-Namen aus dem
procedure-Statement gebildet und der Wert aus dem call-Statement auf diese
lokale Variable kopiert.

Wenn der Parameter per Referenz (Schlüselwort refparam) übergeben wurde, wird
beim Beenden der Procedure das Objekt vom inneren Variablen-Key (param-Name in
der procedure-Deklaration) zum äusseren Variablen-Key (param-Name im call-
Statement) zurückkopiert.

Befehl call
-----------

Der Befehl call ruft eine Prozedur oder Function auf.

    call procedure_name ( [parameter] )

Bei Funktionen kann der Rückgabe-Wert einer Variablen zugewiesen werden.

    session:retval := call procedure_name ( [parameter] )

Es ist aber auch möglich, den Rückgabe-Wert verfallen zu lassen.

Der Aufruf einer CnC-Funktion in einer Expression (Ausdruck) ist nicht möglich,
da die Flow-Engine zwar die Expression-Engine, aber die Expression-Engine nicht
die Flow-Engine aufrufen kann. Das ist die Konsequenz aus der Unterbrechbarkeit
der Flow-Engine.

Im Stack des CnC-Controllers wird die Adresse in der aufrufenden Prozedur für
den return vermerkt.

Es ist möglich der gerufenen Prozedur Parameter mitzugeben. Dabei gibt es value-
Parameter und reference-Parameter.

Referenz-Parameter werden durch das vorgesetzte reservierte Wort 'refparam' in
der procedure- bzw. function-Deklaration gekennzeichnet. Im call-Statement ist
nicht erkennbar, ob es um einen Value- oder einen Referenz-Parameter handelt.

Ich überlege, ob ich den Namen der aufzurufenden Prozedur/Funktion als String-
Expression statt als Bezeichner übergebe. So können Functionpointer nachgebildet
werden, aber die Compiler-Prüfung geht verloren.

Befehl return
-------------

Der Befehl return bricht die Abarbeitung der aktuellen Prozedur/Funktion ab und
kehrt zur aufrufenden Prozedur/Funktion zurück. Falls im Stack des CnC-Status
keine aufrufende Prozedur/Function gefunden werden kann, wird wieder mit dem
Start der procedure main begonnen.

    return; // aus Prozedur

Bei der Rückkehr aus einer Function ist die Rückgabe eines Wertes zwingend erfoderlich.

    return ( <return_expression> ); // aus Function

Falls es keinen Rückgabewert aus einer Funktion gibt, muss

    return(null);

geschrieben werden.

Befehl goto
-----------

Mit dem Befehl goto kann eine Sprungmarke (label) in der main-Prozedur oder ein
Unterprogramm angesprungen werden.

Die Möglichkeit Unterprogramme per goto anzuspringen, dient der Realisierung
globaler Navigationslinks.

Beim Aufruf eines goto wird der vorhandene CnC-Stack verworfen.

Sprungmarken (Label) sind nur in der procedure main erlaubt.

    goto <label_name>;

    goto <procedure_function_name>;

Deklaration label
-----------------

Setzen einer Marke zum Anspringen durch goto.

    label <label_name>;

Label sind nur in der main-Prozedur erlaubt, weil sie dediziert zum Realisieren von
Navigationslinks dienen.

Deklaration while
-----------------

Die Deklaration while umschliesst eine Schleife, bei der vor jedem Durchlauf die
Bedingung zur Ausführung geprüft wird.

    while ( <bedingungs_expression> )
    {
      ...
    } // end while

zum Beispiel

    while ( true ) // Endlos-Schleife
    {
      ...
    } // end while

Die geschwungenen Klammern für den Body sind im Gegensatz zu Java zwingend
erfoderlich.

Deklaration do
--------------

Der Befehl do umschliesst eine Schleife, bei der vor jedem, ausser dem ersten,
Durchlauf die Bedingung zur Ausführung geprüft wird. Ein Durchlauf erfolgt also
immer.

    do ( <bedingungs_expression> )
    {
      ...
    } // end do

oder

    do ( true ) // Endlos-Schleife
    {
      ...
    } // end do

Die geschwungenen Klammern für den Body sind im Gegensatz zu Java zwingend
erfoderlich.


Deklaration for
---------------

Ein for gibt es in CnC nicht, weil ich in einer Fluss-Steuerung
keine Anwendung dafür sehe. Falls es jemand wünscht, kann ich es
aber noch implementieren.


Befehl break
------------

Der Befehl break bricht die aktuelle while- oder do-Schleife ab.

    break;

Befehl continue
---------------

Der Befehl continue springt zum Anfang der aktuellen while-
oder do-Schleife.

    continue ;

Deklaration if, elseif und else
-------------------------------

Über die if-Deklaration kann die bedingte Ausführung von Anweisungen gesteuert
werden.

    if ( <boolean_expression> )
    {
      ...
    } // end if

    //else if ist beliebig oft möglich
    else if ( <boolean_expression> )
    {
      ...
    } // end else if

    else
    {
      ...
    } // end else

Die geschwungenen Klammern für den Body sind im Gegensatz zu Java zwingend
erfoderlich.

Befehl action
-------------

Der Befehl action ruft eine Action-Methode auf. Action-Methoden repräsentieren
den Controller in der MVC-Architektur. Sie werden vom zentralen Servlet
de.cnc.CncServlet unter Mithilfe des ActionMethodClassCache aufgerufen.

Klassen- und Methoden-Name der Action wird als String-Expression übergeben,
wodurch er zur Laufzeit variabel sein kann.

    action ( <name_der_action_als_string> ) ;

Action-Methoden sind static-Methoden in den jeweiligen Action-Klassen mit einer
festgelegten Parameter-Liste.

Der Package-Prefix der Action-Klassen wird durch die Methode
getActionPackagePrefix() und getDefaultActionClassName(), die von der projekt-
spezifischen Ableitung des CncServlet (z.B. CncDemoServlet), implementiert
werden.

Die Notation einer Action-Methode lautet

    "ActionClass#actionMethod"

oder

    "actionMethod"

bei CncDefaultActions#method oder der eigenen Default-Action-Klasse der Applikation
(siehe Methode getDefaultActionClassName() des Applikations-Servlets.

Beispiele sind de.cncdemo.actions.Bestellung und
de.cncdemo.actions.CncDemoDefaultActions, wobei letztere Klase Action-Methoden
enthält, deren Bezeichnungen keinen Prefix (Default) haben.

Der Rückgabe-Wert der Action-Methoden kann für die weitere Verarbeitung
ausgewertet werden.

In Zukunft baue ich noch die optionale Übergabe von Parametern über ein Object-
Array an die Action-Methoden in das Framework ein.


Befehl jsp
----------

Der Befehl jsp zeigt eine JSP an. Hier bleibt der Fluss des CnC-Systems stehen
und wird nach dem nächsten Browser-Request wieder aufgenommen.

Name und Pfad der JSP wird als String-Expression übergeben, wodurch er zur
Laufzeit variabel sein kann.

    jsp ( "pfad und dateiname.jsp als String" );

Die Pfadangabe muß relativ auf das Verzeichnis web (bei Deploment über ant) oder
auf das Verzeichnis der Webapplikation im Tomcat (tomcat.home/webapps/appname)
bezogen erfolgen.

JSP´s stellen den View in der MVC-Architektur dar.

Befehl reset
------------

Löschen eines Wertes von einem bestimmten SessionKey.
Auf dem SessionKey kann ein Objekt beliebiger Klasse liegen.

    reset "sessionKey-String";

Der Befehl reset ist wie der entfallene Befehl set ein Relikt aus der
Zeit der XML-Notation des CnC-Flusses.

Er kann durch

    session:resetVar := null;

ersetzt werden.

Ohne Angabe des SessionKey werden alle Session-Variablen gelöscht.

  reset ( '' ); // löscht alle Session-Variablen

Befehl invalidate
-----------------

Aufruf session:invalidate(), wodurch die aktuelle Session
zerstört und der User aus der Applikation geworfen wird.

    invalidate;

Nach Abarbeitung von invalidate kann auf der aktuellen Session
nicht mehr gearbeitet werden. Auch das Single-Step-Debug bricht
ab.

Deklaration logon
-----------------

Damit das Logon möglich ist, kann für einen Befehlsabschnitt die
User- Validierung ausgeschaltet werden. Dieser Bereich ist nur in
der procedure main gestattet. Für alle Befehle im Flow-Script
ausserhalb des logon-Blockes wird eine User-Validierung
durchgeführt.

logon
{
  ... // nicht geprüfter Bereich
} // logon

Deklaration local
-----------------

Mit dem Befehl localvar werden lokale Variable definiert.

    local sessionKey="..."/>

Die Deklaration local darf nur am Beginn einer Prozedur/Funktion stehen.

Bei Verwendung von local muss die flowleading-Methode auf session stehen, sonst
gibt es einen Runtime-Error. Dies hat seinen Grund darin, dass nicht der gesamte
Stack, dieser kann sehr gross werden, zum Browser und von dort wieder zum Server
gesendet werden soll.

Beim Auftreten von local wird das Objekt vom entsprechenden Session-Key (name="...")
im FlowStack gesichert.

Beim Beenden der procedure oder beim return-Befehl wird das vorherige Objekt
zurückgeschrieben (nur Referenzkopie, kein clone).
Wird der Fluss durch GOTO-Actions oder Fehler verlassen, unterbelibt das zurückschreiben,
der aktuelle Stack verfällt.

Bedingungen
-----------

Bedingungen können in der if-, elseif-, while- und do-Deklaration verwendet werden.

Sie werden durch boolsche Ausdrücke der Expression-Engine realisiert.

    if ( cnc_button == "save )           // Abfragen des Namens des betätigten Buttons

    if ( cnc_button_index >= 0 )         // Abfrage des Index des Buttons in Tabellen (in einfachen Forms -1)

    if ( cnc_link == "Anmeldeformular" ) // Abfrage action="..." der HTML-FORM oder Link HREF="..."
      // Wenn die aufgerufene Action (Dabei wird der Postfix des URL-Pattern *.cnc abgeschnitten) gleich
      // dem übergeben String ist, wird der entsprechende Befehl ausgeführt.

    if ( session:var == null )           // Abfrage Session-Variable auf nicht Existenz/null

    if ( request.param.userId != null )  // Abfrage Request-Parameter auf Existenz/nicht null

Bedingung Link indiziert noch nicht implementiert

Debugging
---------

Zum Debugging stehen folgende Möglichkeiten zur Verfügung:

1. Ausgabe Status über Tag <cnc:debug/> in der JSP-Seite

2. Einzelschritt-Debug über singlestepdebug.jsp

   Einschalten im Script über

    session:CNC_SINGLE_STEP_DEBUG := "ON";

3. Logging ins Tomcat-Startfenster bei Log-Level DEBUG

4. Ausgabe der Steuertabelle (Low-Level-Anweisungen) auf Datei zum Debugging

    Sehen Sie bitte hierzu die auskommentierte Zeile in CncServlet#init.

    //StringUtil.str2file( "" + FlowControl.getFlowControlTable() , "C:\\cnc\\debug\\flow.out" ) ;


Reservierte Bezeichner
----------------------

CnC arbeitet extensiv mit reservierten Session- und Request-Keys um seine
Funktionalität zu realisieren. Diese dürfen von der Applikation nicht benutzt
werden. In den Klassen de.cnc.SessionKeys und de.cnc.RequestKeys sind
entsprechende Konstanten festgelegt.

Prinzipiell sollten Sie Namen die mit 'cnc' oder 'CNC beginnen sowie 'cnc' oder
'CNC' enthalten vermeiden.

Unterdrücken des Caching im Browser
-----------------------------------

In der Betriebsart Session-Leading ist es wichtig, das Caching der HTML-Seiten im Browser zu verhindern,
weil die Applikation sonst verwirrendes Verhalten zeigt. Üblicherweise muss auch auch noch der Cache eines
eventuell vorhandenen Proxys unterdrückt werden.
Dazu muss folgender Code in allen JSPs eingebaut werden:

<meta http-equiv="expires" content="Thu, 26 Dec 2000 00:00:00 GMT">
<meta http-equiv="pragma" content="no-cache">
<% response.addHeader( "Cache-Control" , "no-cache, must-revalidate" ) ; // unterdrücken Seiten-Caching %>

oder

response.addHeader("Cache-Control", "no-cache");
response.addHeader("Expires", "Thu, 26 Dec 2000 00:00:00 GMT");

Oder aufwändiger:

SimpleDateFormat f = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("GMT"));
String lastModified = f.format(new java.util.Date()) + " GMT";
response.setHeader("Last-Modified", lastModified);
response.setHeader("Expires","Thu, 26 Dec 2000 00:00:00 GMT");
response.setHeader("Cache-Control","no-cache, must-revalidate");
response.setHeader("Pragma","no-cache");

Dafür gibt es das Tag <cnc:nocache>

Das zentrale Servlet de.cnc.CncServlet enthält bereits entsprechenden Code.
Weitere Servlets existieren in CnC-Applikationen nicht.

Arbeit mit Frames
-----------------

Wenn mehrere Frames verwendet werden, geht die Synchronisation
beim Flow-Control-Mode Session-Leading verlorden.

Das liegt daran, dass aus den verschiedenen Frames zu
unterschiedlichen Zeitpunkten Requests an den Server abgesendet werden können.

Der Flow-Control-Mode Session-Leading kontrolliert mit einer sich
laufend ändernden Nummer (Synchronisations-Token), ob nicht der
Back-Button benutzt wurde oder ein neues Browserfenster geöffnet
wurde.

Eine Alternative wäre die Benutzung des Flow-Control-Mode Browser-Leading,
welcher aber keine Unterprogramme (ausschliesslich procedure main) erlaubt.

Einen Ausweg ist die Benutzung der Optionen 'target' und
'cncStatusNoCheck="true"' des cnc:hrefgoto-Tags.

In der Datei 'web.xml' muss der Schalter 'synchronized' fuer die Synchronisation
der doRequest-Methode des CnCServlet auf 'true' gesetzt werden, damit es nicht
zu Wettlaufproblemen bei den Request's in den unterschiedlichen Frames kommt.
Ohne Frames sollte 'synchronized' aus Performancegruenden 'false' gesetzt werden.

Die Applikation muss so gestaltet werden, dass in jedem Frame
eine eigene Prozedur, welche über das cnc:hrefgoto-Tag
angesteuert wird, gestartet wird.

Es sollten keine JSP-Seiten direkt in den einzelnen Frames
angesteuert werden, weil sich dann eventuell die Wurzel der Web-
Applikation (im CnC-Demo-Beispiel von
http://localhost:8080/cncdemo auf
http://localhost:8080/cncdemo/frames) verschiebt und der Fluss-
Steuerung die Kontrolle entzogen wird.

Als erstes benötigen wir eine Seite mit einem Frameset

<html lang="de">
 <head>
  <title>CnC Demo Arbeit mit Frames main_frame.jsp</title>
  <link rel="stylesheet" type="text/css" href="cnc.css">
 </head>
 <frameset cols="30%,70%">
   <frame src="cnc_goto_frame_menu.cnc?CNC_STATUS=cncStatusNoCheck&CNC_SRC_JSP=/frame_main.jsp"  name="LeftFrame">
   <frame src="cnc_goto_frame_empty.cnc?CNC_STATUS=cncStatusNoCheck&CNC_SRC_JSP=/frame_main.jsp" name="RightFrame">
  <noframes>
   Ihr Browser kann diese Seite leider nicht anzeigen!
   <cnc:hrefgoto href="begin" txt="Haupt-Menü"/>
  </noframes>
 </frameset>
</html>

Noch zu tun: eigene User-definierte-Tags für <frame src="...

Vom Hauptframe wird über cnc_goto_ an Prozeduren (zur Erinnerung:
über CnC-Gotos können Labels in der procedure main oder
Prozeduren angesprungen werden)

Dabei wird über den Parameter CNC_STATUS=cncStatusNoCheck die
Prüfung des CnC-Status ausgeschaltet.

In der Fluss-Steuerdatei flow.cnc werden die jeweiligen
Prozeduren

//***********************************
procedure frame_menu()
{
  jsp( "/frames/frame_menu.jsp" );
}
//***********************************
procedure frame_empty()
{
  jsp( "empty.jsp" );
}
//***********************************

Wenn zum Beispiel der linke Frame als Menü-Frame dient, muss die
Weiterleitung in den rechten Frame mit
CNC_STATUS=cncStatusNoCheck erfolgen:

<cnc:hrefgoto
  href="frame_table_kunden" -- eine flow.cnc-Prozedur
  target="RightFrame"       -- Name des Zielframes
  cncStatusNoCheck="true"   -- CnC-Status-Check aus
  txt="Kunden-Liste"/>      -- Link-Text


Denkbare Erweiterungen
----------------------

Denkbar wäre eine Möglichkeit eigene Befehle ähnlich wie Custom-
Tags in die Script-Sprache einzubringen. Solche Befhle müssten
aus einem Java-Code-Teil, der ein bestimmtes Interface
implementiert, und aus einer Deklaration der Syntax und des
Verhaltens über eine Description-Datei in XML oder über
Assertions bestehen.

Zur Abbildung von Web-Apps mit Frames könnte man  eine Art
Multithreading einbauen.

Die vorhandene Infrastruktur der Fluss-Steuerung eignet sich
herausgelöst als Fluss-Steuerung (Workflow-Engine) für GUI-
Applikationen (Ersatz von Status-Schaltern oder Finite-State-
Machines) oder für J2EE-Applikationen.

Achtung: Erweiterungen und Fixes stelle ich ohne Historie und ohne Ankündigung hier bereit.
Deshalb am besten immer die letzte Version runterladen.

Lizenzbedingungen:

Die Programme, Quelltexte und Dokumentationen können ohne irgendwelche Bedingungen kostenlos verwendet werden.
Sie sind Freeware und Open Source. Für Fehler und Folgen wird keinerlei Haftung übernommen.

Hinweise zur Fehlerbeseitigung und Verbesserung sind mir willkommen.

Ich freue mich auch über Feedback bezüglich der erfolgreichen Verwendung meiner Sourcen.

Bei Fragen helfe ich gern mit Hinweisen oder zusätzlicher Dokumentation, falls ich dafür Zeit habe.