<SCHEDULE/> Asynchronous rule execution
Connecting external logic to dynamic forms
Using the <SCHEDULE/> tag, external logic (via a service) can be integrated in a dynamic form. This means that the actual validation logic is stored outside in a FirstSpirit module (“asynchronous rule execution”).
To do this, the related module must be installed on the FirstSpirit server prior to executing the rule.
The <SCHEDULE/> section of a rule definition is used to determine values via an external service and in this case replaces the <WITH/> section of a conventional rule definition. The <SCHEDULE/> section must be defined within the tags that specify a restriction level and must be defined before tags that introduce a handling instruction.
In the process, the following applies for the definition of a value determination:
- A value determination must be defined for each rule. This can be done the usual way using a <WITH/> section or, if external logic is used, via a <SCHEDULE/> section.
- Another option is to define a <CONDITION/> tag within a <SCHEDULE/> section.
The <CONDITION/> tag corresponds to the definition of a precondition <IF/> in the case of the conventional rule definition. A Boolean value is determined using the condition. If the condition is fulfilled (TRUE), the defined service is requested; if not (FALSE), the service is not requested. If no condition is defined, the service is always requested.
The precondition is always related to a particular property of the form element or of the form (“Was the form opened in the page store?”). A <PROPERTY/> tag needs to be entered in the <CONDITION/> section for this purpose. Additional values can be derived via one of the following:
The value of the input component, for example, can be checked against certain regular expressions or against a comparison value. - If the value determination is transferred from SiteArchitect to a FirstSpirit module, parameters and values can be sent to the external logic within a <SCHEDULE/> section, such as the current values from an input component of the form. At a minimum, a <PROPERTY/> tag and any other required tags must be entered within a <PARAM/> tag.
- Three attributes can be passed in a <SCHEDULE/> tag. The name of an external class can be entered using the mandatory “service” attribute, a freely selectable identifier can be defined using the mandatory “id” attribute, and a delay for the execution of the passed service can be defined using the optional “delay” attribute; for example:<SCHEDULE service="Keywords" id="x" delay="500">
The following applies when implementing external logic:
- Only a single component of the “Public” type module can be referenced via each <SCHEDULE/> tag.
- To implement a service, the ValueService interface must be implemented: public class MyValueService implements ValueService {...}
- The return value (i.e. the object type) of the ValueService.getValue() implementation should match the desired (target) input component.
- The transfer parameters (see <PARAM/>) are always of the object type and accordingly must be cast in the implementation.
- Values from FirstSpirit input components can be used within a ValueService implementation. This functionality is only supported for the following input components:
- Values of more complex input components (such as FS_DATASET, FS_REFERENCE) cannot be used within ValueService implementations.
service attribute
The “service” attribute is used to reference a single public component of the module.
The name of the public component that is defined under <name> in the component module descriptor is passed, which in this case would be <SCHEDULE service='Keywords'.../>:
...
<components>
<public>
<name>Keywords</name>
<class>mypackage.Keywords</class>
</public>
</components>
...
id attribute
The “id” attribute is used to assign an identifier. If the public component is referenced multiple times within the rule definition, “similar” calls can be avoided by assigning different identifiers in the <SCHEDULE/> sections.
For instance, if (depending on the rule definition) the “Keywords” service is started and is already an active service with the specified service name/ID combination, the existing service call is canceled.
<RULES>
...
<SCHEDULE service="Keywords" id="k1" delay="500">
...
</SCHEDULE>
<DO>
....
</DO>
</RULES>
<RULES>
...
<SCHEDULE service="Keywords" id="k2" delay="500">
...
</SCHEDULE>
<DO>
....
</DO>
</RULES>
delay attribute
The optional “delay” attribute is used to specify a waiting time in milliseconds. The value “0” is always used if no value is entered. If a value greater than “0” is entered, the execution time of the actual service call is delayed according to the value entered.
Background: External logic is integrated in a <SCHEDULE/> section that reads out and processes the values of a FirstSpirit input component and populates a second input component, for instance. This makes it possible to populate the “zip code” field automatically after entering the “location” and “street” in a form. If the external call is returned after one of the affected fields has been changed (e.g. because a typo in the “location” field has since been corrected), the supplied result is discarded again. This behavior is not desired in all cases, since the external call is potentially time and resource intensive. A call for each time the editor presses a button should be prevented by entering the “delay” attribute.
In the case of more complex queries or a very extensive rule definition, it might also make sense to define a precondition using a <CONDITION/> tag. |
Examples
Example 1) Automatic generation of keywords from the value in an input window
A form contains an input window for entering editorial content (“st_text”) and another window for entering keywords (“st_keywords”). Using a dynamic form should now ensure that the content entered by the editor in the first window is automatically copied over to the second input window as keywords. The external logic for this is stored out in a module that first has to be installed on the FirstSpirit server: FirstSpirit ValueService (example) (Version 0.1)
The rule definition then contains a <SCHEDULE/> section defined with the following attributes:
<RULES>
<ON_EVENT>
<SCHEDULE service="Keyword service" id="x" delay="500">
...
</SCHEDULE>
</ON_EVENT>
</RULES>
This syntax is used to request the “Keyword service” under the “x” ID with a delay of 500 ms. However, the service should not be requested continuously, but only when the editor places values in the “st_text” input window. The rule definition is therefore expanded within the <SCHEDULE/> section to include a condition (<CONDITION/>):
<RULES>
<ON_EVENT>
<SCHEDULE service="Keyword service" id="x" delay="500">
<CONDITION>
<PROPERTY source="st_text" name="FOCUS"/>
</CONDITION>
...
</SCHEDULE>
</ON_EVENT>
</RULES>
The “Keyword service” is now only requested when the editor makes the “st_text” component the focus in the form.
The next step is to read out the content from the “st_text” component. In this case the values are transferred to the external logic (i.e. the service). To do this, parameters are passed in the <SCHEDULE/> section (and under the <CONDITION/>, if applicable) using one or more <PARAM/> tags. The “name” attribute is used to define the parameter name. The value determination is then made as usual using a <PROPERTY/> tag within the <PARAM/> section. In this example, the current content of the “st_text” input component and the editorial language in which the form is currently being edited are passed:
<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>
The “text” and “lang” parameter value pairs are transmitted to the service and are further processed there (entry point for the implementation of a value service, see FirstSpirit Developer API: ValueService); for instance:
...
public Object getValue(final SpecialistsBroker broker, final Map<String, ?> parameters) {
final Locale locale;
final Object lang = parameters.get("lang");
...
The <DO/> section of the rule is executed after executing the service with the return value determined there. In the example, the determined return values are applied to the “st_keywords” component.
<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>
Example 2) Checking the validity of an ISBN
A form contains a text input window for entering an ISBN number (“cs_isbn13”). Using a dynamic form ensures that the value of the input component is checked when saved. This check is executed using an external “ISBN13VerificationService” service:
<ON_EVENT>
<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="Please enter a valid 13-digit ISBN!"/>
</VALIDATION>
</DO>
</ON_EVENT>
The ValueService.getValue() implementation checks the number and returns a Boolean value.
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;
}
The returned value is then evaluated in the <VALIDATION/> section of the rule.