<SCHEDULE/> Asynchrone Regelausführung
Anbindung externer Logik an dynamische Formulare
Mithilfe des Tags <SCHEDULE/> kann externe Logik (über einen Service) in ein dynamisches Formular eingebunden werden. Das bedeutet, die eigentliche Validierungs-Logik wird in ein FirstSpirit-Modul ausgelagert („Asynchrone Regelausführung“).
Dazu muss das zugehörige Modul vor der Regelausführung auf dem FirstSpirit-Server installiert werden.
Der <SCHEDULE/>-Abschnitt einer Regeldefinition dient der Wertermittlung über einen externen Service und ersetzt in diesem Fall den <WITH/>-Abschnitt einer herkömmlichen Regeldefinition. Der <SCHEDULE/>-Abschnitt muss innerhalb der Tags definiert werden, die eine Restriktionsstufe festlegen und vor den Tags, die eine Handlungsanweisung einleiten.
Dabei gilt für die Definition einer Wertermittlung:
- Für jede Regel muss eine Wertermittlung definiert werden. Das kann auf herkömmlichen Weg über einen <WITH/>-Abschnitt erfolgen oder, wenn externe Logik verwendet werden soll, über einen <SCHEDULE/>-Abschnitt.
- Optional kann ein <CONDITION/>-Tag innerhalb eines <SCHEDULE/>-Abschnitts definiert werden.
Das <CONDITION/>-Tag entspricht der Definition einer Vorbedingung <IF/> bei der herkömmlichen Regeldefinition. Über die Bedingung wird ein Boolescher Wert ermittelt. Ist die Bedingung erfüllt (TRUE) wird der definierte Service angefordert, im Negativfall (FALSE) nicht. Ist keine Bedingung definiert wird der Service immer angefordert.
Die Vorbedingung bezieht sich immer auf eine bestimmte Eigenschaft des Formularelements (z. B. „Ist die Eingabekomponente fokussiert?“) oder auch des Formulars („Wurde das Formular in der Inhalte-Verwaltung geöffnet?“). Dazu ist die Angabe eines <PROPERTY/>-Tags innerhalb des <CONDITION/>-Abschnitts notwendig. Über:
können weitere Werte abgeleitet werden. So kann der Wert der Eingabekomponente beispielsweise gegen bestimmte reguläre Ausdrücke oder gegen einen Vergleichswert geprüft werden. - Wird die Wertermittlung vom JavaClient auf ein FirstSpirit-Modul übertragen, können innerhalb eines <SCHEDULE/>-Abschnitts Parameter und Werte an die externe Logik übergeben werden, beispielsweise der aktuelle Werte aus einer Eingabekomponente des Formulars. Innerhalb eines <PARAM/>-Tags ist dazu mindestens die Angabe eines <PROPERTY/>-Tags und ggf. weiterer Tags notwendig.
- In einem <SCHEDULE/>-Tag können drei Attribute übergeben werden. Über das Pflicht-Attribut „service“ wird der Name einer externen Klasse angegeben, über das Pflicht-Attribut „id“ ein freiwählbarer Identifier und über das optionale Attribut „delay“ kann eine Verzögerung für die Ausführung des übergebenen Services definiert werden, z. B.:<SCHEDULE service="Keywords" id="x" delay="500">
Für die Implementierung der externen Logik gilt:
- Über jedes <SCHEDULE/>-Tag kann immer nur eine einzelne Komponenten des Moduls vom Typ „Public“ referenziert werden.
- Für die Implementierung eines Services muss das Interface ValueService implementiert werden: public class MyValueService implements ValueService {...}
- Der Rückgabewert (also der Objekttyp) der ValueService.getValue()-Implementierung sollte zur gewünschten (Ziel-)Eingabekomponente passen.
- Die Übergabeparameter (siehe <PARAM/>) sind immer vom Typ Object und müssen in der Implementierung entsprechend gecasted werden.
Attribut service
Über das Attribut „service“ kann eine einzelne Public-Komponente des Moduls referenziert werden.
Übergeben wird hier der Name der Public-Komponente, der unter <name> im Komponenten-Modul-Deskriptor definiert wird, hier <SCHEDULE service='Keywords'.../>:
...
<components>
<public>
<name>Keywords</name>
<class>mypackage.Keywords</class>
</public>
</components>
...
Attribut id
Über das Attribut „id“ kann ein Identifier vergeben werden. Wird die Public-Komponente innerhalb der Regeldefinition mehrfach referenziert, können über die Vergabe unterschiedlicher Identifier in den <SCHEDULE/>-Abschnitten "gleichartige" Calls vermieden werden.
Wird also (abhängig von der Regeldefinition) z. B. der Service „Keywords“ gestartet und ist bereits ein Service mit der angegebenen Servicename-ID-Kombination aktiv, wird der bestehende Serviceaufruf abgebrochen.
<RULE>
<SCHEDULE service="Keywords" id="k1" delay="500">
...
</SCHEDULE>
<DO>
....
</DO>
</RULES>
<RULES>
<SCHEDULE service="Keywords" id="k2" delay="500">
...
</SCHEDULE>
<DO>
....
</DO>
</RULES>
Attribut delay
Über das optionale Attribut „delay“ kann eine Wartezeit in Millisekunden festgelegt werden. Ohne Angabe eines Wertes wird immer „0“ als Wert angenommen. Ist ein Wert größer „0“ angegeben, wird die Ausführung des eigentlichen Dienstaufrufs um die entsprechende Zeit verzögert.
Hintergrund: Innerhalb eines <SCHEDULE/>-Abschnitts wird externe Logik eingebunden, die beispielsweise die Werte einer FirstSpirit-Eingabekomponente ausliest, verarbeitet und eine zweite Eingabekomponente füllt. So kann beispielsweise nach der Eingabe von „Ort“ und „Straße“ in einem Formular, automatisch das Feld „Postleitzahl“ gefüllt werden. Kommt der externe Call zurück, nachdem sich eines der betroffenen Felder wieder geändert hat (z. B. weil ein Tippfehler im Feld „Ort“ mittlerweile korrigiert wurde, muss das gelieferte Ergebnis wieder verworfen werden. Dieses Verhalten ist in vielen Fällen nicht erwünscht, da der externe Call potentiell zeit- und ressourcenintensiv ist. Ein Aufruf bei jedem Tastendruck des Redakteurs sollte durch die Angabe des Attributs „delay“ unterbunden werden
Bei komplexeren Abfragen oder einer sehr umfangreichen Regeldefinition kann es außerdem sinnvoll sein, eine Vorbedingung mittels eines <CONDITION/>-Tags zu definieren. |
Beispiele
Beispiel 1) Automatische Generierung von Keywords aus dem Wert eines Eingabefelds
In einem Formular gibt es je ein Eingabefeld für die Eingabe von redaktionellen Inhalten („st_text“) und ein weiteres Feld zur Eingabe von Schlüsselwörtern („st_keywords“). Über ein dynamisches Formular soll nun sichergestellt werden, dass die Inhalte, die vom Redakteur in das erste Feld eingetragen werden, automatisch als Schlüsselworte in das zweite Eingabefeld übernommen werden. Die externe Logik dazu wird in ein Modul ausgelagert, das zunächst auf dem FirstSpirit-Server installiert werden muss: FirstSpirit ValueService (Example)
Innerhalb der Regeldefinition wird dann ein <SCHEDULE/>-Abschnitt mit den folgenden Attributen definiert:
<RULES>
<ON_EVENT>
<SCHEDULE service="Keyword service" id="x" delay="500">
...
</SCHEDULE>
</ON_EVENT>
</RULES>
Über dieses Tag wird der Dienst „Keyword service“ unter der ID „x“ mit einer Verzögerung von 500 ms angefordert. Der Dienst soll jedoch nicht ständig angefordert werden, sondern nur, wenn der Redakteur Werte im Eingabefeld „st_text“ hinterlegt. Die Regeldefinition wird daher innerhalb des <SCHEDULE/>-Abschnitts um eine Bedingung (<CONDITION/>) ergänzt:
<RULES>
<ON_EVENT>
<SCHEDULE service="Keyword service" id="x" delay="500">
<CONDITION>
<PROPERTY source="st_text" name="FOCUS"/>
</CONDITION>
...
</SCHEDULE>
</ON_EVENT>
</RULES>
Der Dienst „Keyword service“ wird jetzt nur noch angefordert, wenn die Komponente „st_text“ vom Redakteur im Formular fokussiert wird.
Im nächsten Schritt sollen die Inhalte aus der Komponente „st_text“ ausgelesen werden. In diesem Fall müssen die Werte an die externe Logik (also den Dienst) übermittelt werden. Dazu erfolgt innerhalb des <SCHEDULE/>-Abschnitts (und ggf. unterhalb der <CONDITION/>) eine Parameterübergabe mittels eines oder mehrerer <PARAM/>-Tags. Über das Attribut „name“ wird der Parametername definiert. Die Wertermittlung erfolgt dann wie gewohnt über ein <PROPERTY/>-Tag innerhalb des <PARAM/>-Abschnitts. In diesem Beispiel wird der aktuelle Inhalt der Eingabekomponente „st_text“ und die Redaktionssprache, in der das Formular aktuell bearbeitet wird, übergeben:
<RULES>
<ON_EVENT>
<SCHEDULE service="Keyword service" id="x" delay="500">
<CONDITION>
<PROPERTY source="st_text" name="FOCUS"/>
</CONDITION>
<PARAM name="text">
<PROPERTY source="st_text" name="VALUE"/>
</PARAM>
<PARAM name="lang">
<PROPERTY source="#global" name="LANG"/>
</PARAM>
</SCHEDULE>
</ON_EVENT>
</RULES>
Die Parameter-Wert-Paare „text“ und „lang“ werden an den Service übermittelt und dort weiterverarbeitet (Einstiegspunkt für die Implementierung eines ValueServices siehe FirstSpirit-Developer-API: ValueService), z. B.:
...
public Object getValue(final SpecialistsBroker broker, final Map<String, ?> parameters) {
final Locale locale;
final Object lang = parameters.get("lang");
...
Der <DO/>-Abschnitt der Regel wird nach der Ausführung des Dienstes mit dem dort ermittelten Rückgabewert ausgeführt. Im Beispiel sollen die ermittelten Rückgabewerte in die Komponente „st_keywords“ übernommen werden.
<RULES>
<ON_EVENT>
<!-- SCHEDULE Tag -->
<SCHEDULE service="Keyword service" id="x" delay="500">
<CONDITION>
<PROPERTY source="st_text" name="FOCUS"/>
</CONDITION>
<PARAM name="text">
<PROPERTY source="st_text" name="VALUE"/>
</PARAM>
<PARAM name="lang">
<PROPERTY source="#global" name="LANG"/>
</PARAM>
</SCHEDULE>
<!-- /SCHEDULE Tag -->
<!-- DO Tag -->
<DO>
<PROPERTY source="st_keywords" name="VALUE"/>
</DO>
<!-- /DO Tag -->
</ON_EVENT>
</RULES>
Beispiel 2) Prüft die Gültigkeit einer ISBN
In einem Formular gibt es ein Text-Eingabefeld für die Eingabe einer ISBN-Nummer („cs_isbn13“). Über ein dynamisches Formular soll nun sichergestellt werden, dass der Wert der Eingabekomponente beim Speichern geprüft wird. Diese Prüfung wird über den externen Dienst „ISBN13VerificationService“ ausgeführt:
<ON_SAVE>
<SCHEDULE service="ISBN13VerificationService" id="isbn13" delay="0">
<PARAM name="value">
<PROPERTY source="cs_isbn13" name="VALUE"/>
</PARAM>
</SCHEDULE>
<DO>
<VALIDATION>
<PROPERTY source="cs_isbn13" name="VALID"/>
<MESSAGE lang="*" text="Es muss eine gültige ISBN-13-Nummer angegeben werden!"/>
</VALIDATION>
</DO>
</ON_SAVE>
Die ValueService.getValue()-Implementierung prüft die Nummer und liefert einen Booleschen Wert zurück.
public Boolean getValue(final SpecialistsBroker broker, final Map<String, ?> parameters) {
final Object value = parameters.get("value");
if (value instanceof String) {
log("Performing ISBN-13 verification...");
return isValidISBN13((String) value);
}
return false;
}
Der zurückgelieferte Wert wird anschließend im <VALIDATION/>-Abschnitt der Regel ausgewertet.