Qorus Integration Engine® Enterprise Edition 6.0.16_prod
Loading...
Searching...
No Matches
Deprecated Mixed Code and Metadata File Formats

Table of Contents

Back to the Developer's Guide Table of Contents

Qorus Integration Engine™ introduced YAML metadata files for Qorus integration object metadata separate from code files in version 4.1, deprecating support for old-style file formats with mixed code and metadata as special comments in the code.

The Qorus IDE does not support the old mixed code and metadata file formats for Qorus development.

As Python support was introduced in Qorus 5, for example, Python is only supported in new objects with separate YAML metadata files.

The old mixed code and metadata formats will continue to be supported for backwards compatibility, however it is not recommended to use this format for any new developments.

Deprecated Workflow File Format Descriptions

Deprecated Qore-Language Workflow Definition File

In Qore-language workflow definition files, the actual workflow definitions are made by assigning values to the workflows variable in the workflow description file. The top-level keys represent the version(s) of the workflow(s) being described, and the member data of each version key defines that version of the workflow. For a description of this variable, see Workflow Definitions.

The format_version variable in the workflow definition file must be set to "2.6" to declare compatibility with the workflow definition file format documented in this manual.

In order to describe the metadata to the loader (oload), variables with pre-defined names and a pre-defined structure must be defined in this file.

Qore Workflow Definition File Variables

Variable Description
format_version Set to "2.6" to declare compatibility with the oload format defined in this documentation for Qorus 6.0.16_prod
workflows Defines workflow metadata
queues Defines asynchronous queues
groups Defines interface groups
events Defines workflow synchronization events

Any other variables, functions, and classes defined in the file will be ignored unless explicitly executed in the script (for example, when building the workflows or queues data structures).

Deprecated Workflow Definitions

The "workflows" variable in a Qore workflow definition file must declare a hash defining workflow metadata.

Note
In a deprecated Qore workflow definition file, the top-level keys in the "workflows" global variable represent workflow names; these keys must also be assigned to a hash, where each key is a version of the workflow being defined. The value assigned to each version key must be a workflow description hash, representing the workflow metadata definition.

The workflow description hash has the following keys (optional keys are enclosed in square brackets []):

  • author: the author of the workflow
  • steps: step definitions and dependencies
  • workflow-modules: lists modules providing new step base classes for step classes
  • [remote]:flag that indicates if a workflow can run in a remote qwf process or not (see qorus-client.remote for how the default value is assigned by oload)
  • [autostart]: the number of workflow execution instances to start when the system starts
  • [sla_threshold]: the amount of time as an integer in seconds in which each workflow order should get a final status; if not present the default value of 30 minutes is assumed (see DefaultWorkflowSlaThreshold)
  • [max_instances]: the maximum number of workflow execution instances that can be started
  • [attach]: attach function description (ex: "my_attach:1.0"); cannot be supplied if "class" is used
  • [detach]: detach function description (ex: "my_detach:1.0"); cannot be supplied if "class" is used
  • [onetimeinit]: one time initialization function description (ex: "my_workflow_init:1.0"); cannot be supplied if "class" is used
  • [classes]: list of class objects to load into the workflow's Program space
  • [constants]: list of constant objects to load into the workflow's Program space
  • [functions]: list of function objects to load into the workflow's Program space
  • [mappers]: list of mappers to register with the workflow so they are available with the UserApi::getMapper() call in the workflow's code
  • [vmaps]: list of value maps to register with the workflow so they can be used with the UserApi::getValueMap() call in the workflow's code
  • [options]: a hash defining valid workflow options
  • [keylist]: a list of valid workflow keys
  • [groups]: list of Interface Groups the workflow will belong to
  • [error_handler]: error handler function description (ex: "my_error_handler:1.0"); cannot be supplied if "class" is used
  • [errorfunction]: error function description (ex: "my_error_func:1.0"); cannot be supplied if "class" is used
  • [statuses]: a hash defining extended custom status descriptions as a single character key - string description

Here step and function designators (except for in the "functions" tag above) define a specific version of the appropriate object. This is done by specifying a string in the following format: "name:version" or by specifying a hash with name and version keys set to the appropriate values.

Workflow Definition Example

%new-style
%require-types
%strict-args
%enable-all-warnings
# set format_version to "2.6"
our string format_version = "2.6";
# the groups variable defines interface groups; this group is referenced in the workflow below
our hash<auto> groups.test.desc = "test interfaces";
# the options variable will be used in the workflow definition below
our hash<auto> options = (
"test-mode" : "enable test error generation",
"fast-exec" : "enable simplified execution",
);
# defines workflow EXAMPLE version 1.0
our hash<auto> workflows.EXAMPLE."1.0" = {
# the "desc" key sets the description for the workflow
"desc": "simple example workflow with 3 linear steps",
# the "author" key documents the author of the workflow
"author": "Josephine Programmer",
# the "steps" key defines the steps and describes the step dependencies, in this
# example there are three steps with linear dependencies; the steps are normal
# steps given as classes with the name and version which will describe the name
# and version of the step corresponding to the name and version of the step class
"steps": (
"class:MyTestStep1:1.0",
"class:MyTestStep2:1.0",
"class:MyTestStep3:1.0",
),
# the "workflow-modules" option lists modules providing new step base classes
"workflow-modules": ("MyWorkflowModule1", "MyWorkflowModule2"),
# the "remote" key sets the flag that indicates if the workflow can run in a remote
# "qwf" process if True (the default if not present), or if it must run as an embedded
# workflow in "qorus-core" if False
"remote": True,
# the "autostart" key sets the number of workflow execution instances to be started
# when the system is started; if the system should ensure that this workflow is
# generally running, then set this key to a value > 0
"autostart": 1,
# the "sla_threshold" key sets the amount of time as an integer number of seconds in
# which workflow orders should get a final status and is used for reporting in the
# REST and WebSocket APIs; the default value if not present is 1800 indicating 30
# minutes; the example value here means 20 seconds
"sla_threshold": 20,
# the optional "max_instances" key sets the maximum number of workflow execution
# instances that can be running at one time; note that workflow execution instances
# are capable of processing up to two orders in parallel at any one time (one in
# "normal" mode and one in "recovery" mode).
"max_instances": 1,
# the optional "constants" key sets constant objects to be loaded into the
# workflow's program object; no version may be given for constants
"constants": ("TestConstants1", "TestConstants2"),
# the optional "classes" key defines class objects to be loaded into the
# workflow's program object; no version may be given for classes
"classes": ("TestClass1", "TestClass2"),
# the optional "functions" key defines function objects to be loaded into the
# workflow's program object; no version may be given for functions
"functions": ("TestFunction1", "TestFunction2", "doTest"),
# the optional "mappers" key defines mappers that are registered to the
# workflow which can be retrieved with UserApi::getMapper(); a version key must
# be found in the string;
"mappers": ("my-mapper-1:1.0", "my-mapper-2:1.0",),
# the optional "vmaps" key defines value maps that are registered to the
# workflow which can be used with UserApi::getValueMap(); no version key may be
# given with value maps
"vmaps": ("my-vmap-1", "my-vmap-2",),
# the optional "attach" key defines the attach function for the workflow
"attach": "attach_test:1.0",
# the optional "detach" key defines the detach function for the workflow
"detach": "detach_test:1.0",
# the optional "error_handler" key defines the error handler function
"error_handler": "error_handler_test:1.0",
# the optional "errorfunction" key defines the error definition function
"errorfunction": "test_errors:1.0",
# the optional "onetimeinit" key defines the one-time initialization function
"onetimeinit": "test_onetimeinitialization:1.0",
# the optional "options" key defines workflow options (see options var above)
"options": options,
# the optional "keylist" key defines valid workflow order data keys
"keylist": ("account-id", "customerno"),
# the optional "groups" key adds the workflow to the given interface groups
"groups": "test"
# the optional "statuses" hash defines descriptions for single character custom status codes
"statuses": {
"F": "Filename is already registered with another order. Check it manually",
"I": "Possible inconsistency between stage and cache. Check it manually",
"M": "Missing input file. Order was canceled probably. Check it manually",
"D": "Detach function failed. Check it in the log file",
},
};

See Deprecated Workflow Parameters for details on how to define workflow in the workflow definition file, and see $OMQ_DIR/examples/user/TEST-WORKFLOWS for some example workflow definition files.

Deprecated Queue Definitions

Queues provide the storage and delivery mechanism by which the results of executing an asynchronous event for an asynchronous step are delivered to the right step instance. The queues variable in the workflow definition file must be set to a hash defining queue metadata. The top-level key gives the queue names, and the member data under the queue is a hash with a the desc key, giving a description of the queue.

  • queues."queuename" = ("desc": "description string" ));

If a workflow has at least one asynchronous step, a queue must be defined. A single queue can be used for any number of asynchronous steps, however the keys in a queue must be unique. See the step queue attribute for more information.

The following are examples of queue definitions:

# example Qore queue definition
our hash<auto> queues."my-async-queue".desc = "Asynchronous queue";
See also

Deprecated Interface Group Definition

In order to allow workflows to declare membership to Interface Groups, the group may be declared in the workflow definition file by assigning a value to the global groups variable.

  • groups."groupname" = ("desc": "description string" ));

The following is an example of a group definition:

# example group definition
our hash<auto> groups."my-group".desc = "my interface group";

Deprecated Workflow Synchronization Event Type Definitions

Workflow synchronization events are used to synchronize processing from multiple workflow orders; each workflow synchronization event has a key that will be bound to the workflow synchronization event step by calling QorusEventStepBase::bindEvent() / Qorus DataProvider API: Bind Workflow Synchronization Event, or QorusEventStepBase::bindEventUnposted() / Qorus DataProvider API: Bind Workflow Synchronization Event Unposted in the step's primary step code. The workflow synchronization event key is unique within it's workflow synchronization event type; as such, the event type can be compared to a queue name.

The workflow synchronization event type is referenced in workflow synchronization event steps in the eventtype tag.

The actual event type definition is made in the workflow definition file by assigning a value to the global events variable:

  • events."eventname" = ("desc": "description string" ));

The following are examples of workflow synchronization event type definitions:

# example Qore workflow synchronization event type definition
our hash<auto> events."my-event".desc = "my event type";
See also

Deprecated Custom Status Codes

In this hash, descriptions for single character keys of custom status codes available for the workflow can be defined.

# example of descriptions for custom status codes
"statuses": {
"F": "Filename is already registered with another order. Check it manually",
"I": "Possible inconsistency between stage and cache. Check it manually",
"M": "Missing input file. Order was canceled probably. Check it manually",
"D": "Detach code failed. Check it in the log file",
)

See

Deprecated Workflow Parameters

The workflow hash description consists of the step dependencies and other attributes.

The following diagram illustrates a subset of the attributes of a workflow.

Workflow Metadata Diagram

Workflow Parameter Descriptions

Parameter Description
author The author of the workflow
steps This is where steps and step dependencies are defined
desc A string giving the description for the workflow
workflow-modules lists modules providing new step base classes for step classes
remote flag that indicates if a workflow can run in a remote qwf process or not (see qorus-client.remote for how the default value is assigned by oload)
autostart the number of workflow execution instances to start when the system starts
[sla_threshold] the amount of time as an integer in seconds in which each workflow order should get a final status; if not present the default value of 30 minutes is assumed (see DefaultWorkflowSlaThreshold)
max_instances the maximum number of workflow execution instances that can be started
classes If defined, this list of strings designates the Qore classes that will be loaded into the workflow's program object from the CLASSES table when the workflow is cached (represented by the "Shared Classes" object in the diagram above). Note that only the Qorus class object name should be given as it appears in the database without any version number, the latest version of the class will be loaded into the workflow's Program object.
constants If defined, this list designates the Qore constant definitions that will be loaded into the workflow's program object from the CONSTANTS table when the workflow is cached (represented by the "Shared Constants" object in the diagram above). Note that only the Qorus constant object name should be given as it appears in the database without any version number, the latest version of the constant will be loaded into the workflow's Program object.
functions If defined, this list designates the Qore function definitions that will be loaded into the workflow's program object from the FUNCTIONS table when the workflow is cached (represented by the "Shared Functions" object in the diagram above). Note that only the Qorus function object name should be given as it appears in the database without any version number, the latest version of the function will be loaded into the workflow's Program object
mappers If defined, this list designates the mappers that will be registered with the workflow so they are available with the UserApi::getMapper() call in the workflow's code; the mapper name must be given with an explicit version number in each string (ex: "my-mapper-1:1.0")
vmaps If defined, this list designates the value maps to register with the workflow so they can be used with the UserApi::getValueMap() call in the workflow's code; no version number can be given in the value map names
attach (only if class) is not defined) If defined, this string identifies a function that will be executed every time Qorus caches and starts working on ("attaches to") a particular workflow order data instance (represented by the "Attach Logic" object in the diagram above). The function's version may be given by appending a colon and the version identifier to the name as follows: "detach_function_name:1.0"
detach (only if class) is not defined) If defined, this string identifies a function that will be executed every time Qorus stops working on ("detaches from") a particular workflow order data instance (represented by the "Detach Logic" object in the diagram above). The function's version may be given by appending a colon and the version identifier to the name as follows: "detach_function_name:1.0".
onetimeinit (only if class) is not defined) If defined, this string identifies a function that will be executed once when each workflow execution instance is started (represented by the "Init Logic" object in the diagram above). The function's version may be given by appending a colon and the version identifier to the name as follows: "onetimeinit_function_name:1.0"
error_handler (only if class) is not defined) If defined, this string identifies a function that will be executed every time an error is raised by the workflow (represented by the "Error Handler" object in the diagram above). The function's version may be given by appending a colon and the version identifier to the name as follows: "error_handler_function_name:1.0"
errorfunction This string identifies a function that is called by Qorus when the workflow definition is loaded by oload (represented by the "Error Definitions" object in the diagram above). It should return a hash of error information. See Workflow Error Handling and Recovery for more information. The function's version may be given by appending a colon and the version identifier to the name as follows: "error_function_name:1.0"
options The options key should be assigned to a hash defining valid workflow options
keylist This key should be assigned to a list giving valid workflow keys for fast lookups of workflow order instance data
groups list of workflow and service groups the workflow will belong to
statuses a hash defining extended custom status descriptions.
Note
It's important to decide carefully whether to use generic functions (or classes) to extend the functionality of a workflow, or to develop a user service. Normally functionality belongs in a user service if it meets one or more of the following criteria:
  1. It will be called from external applications and should be exported through the network API
  2. It will change often or is used by multiple workflows, and it would be desirable to perform live upgrades of the functionality independently of the workflow(s) that depend on it
  3. The functionality is critical and needs to be developed/tested independently of the workflow(s) that depend on it

Deprecated Workflow Definition Options Key

If the options key is defined in the workflow definition, the workflow will advertise and accept only the options defined under this key as valid options for the workflow (aside from system options that can be overridden at the workflow level, which are always accepted as workflow options). Valid options are given as a hash assigned to this key, where the hash keys are the option names, and the values assigned to the keys are the descriptions of the options.

Here is an example of am options declaration in a YAML workflow definition file:

# example workflow definition with options
name: "EXAMPLE-WORKFLOW"
version: "1.0"
desc: "simple example workflow"
steps:
# step definitions here...
options:
account: "override default account code"
summary: "set to True for a summary report"

Here is an example of am options declaration in a deprecated Qore workflow definition file:

# example workflow definition with options
our hash<auto> workflows."EXAMPLE-WORKFLOW"."1.0" = (
"desc": "simple example workflow",
"steps": ( ... ),
"options": {
"account": "override default account code",
"summary": "set to True for a summary report",
},
);

Options set on workflows are persistent; the option values are written to the WORKFLOW_OPTIONS table.

Deprecated Workflow Definition Keylist Key

The workflow definition option keylist defines one or more "order keys" that can be used to quickly look up workflow order data instances. Any number of workflow keys may be given in the workflow definition, in contrast to the single external_order_instanceid that can be given at the workflow order data instance object level and can be used for the same purpose (quickly looking up workflow order data instances from a external key).

Valid keys are defined as per the following examples:

# example YAML workflow definition with a keylist
name: "EXAMPLE-WORKFLOW"
version: "1.0"
desc: "simple example workflow"
keylist: ["account_no", "customer_id"]
# example Qore workflow definition with a keylist
our hash<auto> workflows."EXAMPLE-WORKFLOW"."1.0" = (
"desc": "simple example workflow",
"steps": ( ... ),
"keylist": ("account_no", "customer_id"),
);

Keys can be set and retrieved by the WorkflowApi::setOrderKeys() and WorkflowApi::getOrderKeys() methods (in Qore) or the WorkflowApi.setOrderKeys() and WorkflowApi.getOrderKeys() methods (in Java), respectively. Key metadata is saved in the WORKFLOW_KEYS table, and workflow order data instance keys are saved in the ORDER_INSTANCE_KEYS table. Note that a single key value can be saved for more than one workflow order data instance; the indexes on the ORDER_INSTANCE_KEYS only enforce that values may not be repeated for the same workflow_instanceid and key name.

The REST API provides methods to lookup workflow orders by workflow keys; see the following API for more information:

Deprecated Workflow Definition Groups Key

The workflow definition option groups defines one or more Interface Groups that the workflow is a member of. Interface groups can also be declared in the workflow file using the global groups variable (see Deprecated Interface Group Definition).

Interface group membership is declared as per the following examples:

# example YAML workflow definition declaring membership in an interface group
name: "EXAMPLE-WORKFLOW"
version: "1.0"
desc: "simple example workflow"
groups: "my-group"
Note
Interface groups can be defined using YAML definition file, see Implementing Qorus Objects Using YAML format.
# example Qore workflow definition declaring membership in an interface group
our hash<auto> workflows."EXAMPLE-WORKFLOW"."1.0" = (
"desc": "simple example workflow",
"steps": ( ... ),
"groups": "my-group",
);

Deprecated Workflow Steps

The inter-step dependencies are defined in the steps key in the workflow definition. This section describes how to define step dependencies and simple step definitions. For details on how to define complex steps, see Step Definitions.

The basic format of this data structure is a list. At the top level, a list indicates sequential dependencies, as in the following examples:

# simple YAML example workflow definition
name: "EXAMPLE-WORKFLOW"
version: "1.0"
desc: "simple example workflow"
steps:
- "class:MyStep1:1.0"
- "class:MyStep2:1.0"
- "class:MyStep3:1.0"
# simple Qore example workflow definition
our hash<auto> workflows."EXAMPLE-WORKFLOW"."1.0" = (
"desc": "simple example workflow",
"steps": ("class:MyStep1:1.0", "class:MyStep2:1.0", "class:MyStep3:1.0"),
);

In this example; the workflow EXAMPLE-WORKFLOW 1.0 is created. The step dependencies are linear: MyStep1 has no dependencies and therefore is the starting step, MyStep2 is dependent only on MyStep1, and MyTestStep3 is the final step in the workflow and is dependent only on MyStep2.

Simple Workflow Execution Dependency Diagram

In this simple example, 3 steps will be created (or updated if the steps already exist) with the same names and version specifiers as the class names above and placed in simple linear dependency in the steps list.

Note
Each of the step definitions in this simple example is made in the simplest format possible, which is "class:stepname:version". In this case, the step will have the same name and version as the class that defines the step. That means that classes "MyStep1" version "1.0", "MyStep2" version "1.0", and "MyStep3" version "1.0" must also be defined; See array steps, subworkflow steps, asynchronous steps, validation code, function definition file.

It is possible to create more complex step dependencies. For example, if one of the entries in the top-level steps list is itself a list, then all entries in the sublist have the same dependency and therefore will be executed in parallel threads. Furthermore, of one of the entries in the sublist is also a list, then they will be assigned sequential dependencies (i.e.: be executed sequentially) within this sublist. Using this simple syntax, it is possible to define a complex multithreaded workflow with minimum effort.

Here are more complex examples:

# more complex example YAML Qore workflow definition
name: "EXAMPLE-WORKFLOW"
version: "1.0"
desc: "simple example workflow"
steps:
- name: "step1"
classname: "MyStep1:1.0"
- - - name: "step2"
classname: "MyStep2:1.0"
- name: "step3"
classname: "MyStep3:1.0"
- name: "step4"
classname: "MyStep4:1.0"
- name: "step5"
classname: "MyStep5:1.0"
# more complex example Qore workflow definition
our hash<auto> workflows."COMPLEX-EXAMPLE-WORKFLOW"."1.0" = (
"desc": "complex example workflow",
"steps": (
{"name": "step1", "classname": "MyStep1:1.0"},
(
(
{"name": "step2", "classname": "MyStep2:1.0"},
{"name": "step3", "classname": "MyStep3:1.0"},
),
{"name": "step4", "classname": "MyStep4:1.0"},
),
{"name": "step5", "classname": "MyStep5:1.0"},
),
);

In this example, MyStep1 will be executed first, then 2 threads will start in parallel. In one thread, MyStep2 and MyStep3 will be executed in sequence. In the other thread, MyStep4 will be executed. Only when all of these steps reach a OMQ::StatComplete status, will MyStep5 be executed as the final step in the workflow.

The execution diagram will look like the following:

Complex Workflow Execution Diagram

Using this simple rule of alternating list levels for sequential and parallel execution, it is possible to create very complex multithreaded workflows with minimum effort.


Deprecated Workflow Modules Parameter

The "workflow-modules" option lists modules providing new base classes for step classes as in the following example.

YAML Example:
# defines workflow EXAMPLE version 1.0
name: "EXAMPLE"
version: "1.0"
workflow-modules:
- "MyWorkflowModule1"
- "MyWorkflowModule2"
Qore Example:
# defines workflow EXAMPLE version 1.0
our hash<auto> workflows.EXAMPLE."1.0" = {
# ...
"workflow-modules": ("MyWorkflowModule1", "MyWorkflowModule2"),
# ...
};

Modules declared like this will be loaded into each workflow's Program object, and their classes can be used as base classes for step classes.

See also
Qore-Language Workflow Extension Modules for more information.

Deprecated OneTimeInit Function

Synopsis
This code is executed once when the workflow execution instance starts, and once again after every workflow instance cache reset.
Note: Acquire Workflow Execution Instance Resources in OneTimeInit Logic
Persistent objects with a high acquisition cost should be acquired in the onetimeinit logic. Use the WorkflowApi::updateInstanceData() method (in Qore) or the WorkflowApi.updateInstanceData() method (in Java) to save resources acquired, and WorkflowApi::getInstanceData() (in Qore) or the WorkflowApi.getInstanceData() method (in Java) to retrieve the resources during the workflow's execution.
Workflow Class Method
QorusWorkflow::oneTimeInit()
Function-Based One Time Initialization Logic
It is recommended to use a workflow class to define workflow logic attributes; for old-style function attributes, the signature is as follows:
nothing sub functionname() {}
One Time Initialization Function Definition Example
# type: GENERIC
# version: 1.0
# desc: example workflow initialization
%new-style
%require-types
%strict-args
%enable-all-warnings
sub example_workflow_init() {
object obj = acquire_an_expensive_object();
# save it in instance data
WorkflowApi::updateInstanceData({"obj": obj});
}
# END
Note
It's recommended to use a workflow class instead of functions for the best forward compatibility with future versions of Qorus

Deprecated Attach Function

Synopsis
This code is called when Qorus starts working on a workflow order data instance (when Qorus "attaches" to the workflow order data instance, reading it into memory from the database).

If any error is raised in the attach code (by calling WorkflowApi::stepError() or by throwing an appropriate exception)), the workflow order data instance will receive an OMQ::StatError status and the attach operation will fail.

The recommended way to implement attach logic is to use a workflow class.

Note: Reliably Set TempData in Attach Logic
TempData can only be reliably set in attach code, because a workflow can be restarted from any step after an error. Therefore you cannot ensure that TempData set in step logic will be available when executing the following step, in case an error occurs.
Workflow Class Method
QorusWorkflow::attach()
Function-Based Attach Logic
It is recommended to use a workflow class to define workflow logic attributes; for old-style function attributes, the signature is as follows:
nothing sub functionname() {}
Attach Function Definition Example
# type: GENERIC
# version: 1.0
# desc: example attach function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub example_attach() {
UserApi::logInfo("attach function");
}
# END
Note
It's recommended to use a workflow class instead of functions for the best forward compatibility with future versions of Qorus

Deprecated Detach Function

Synopsis
This code is called when the workflow order data instance status is committed to the database (when Qorus "detaches" from the workflow order data instance). The first argument passed to the function is the workflow order data instance's status (status descriptions) that will be written to the database. The second argument passed is the external order instance ID, if any exists.
Note: Update Processing Status Externally with Detach Logic
Because detach logic is called any time the workflow order data instance status is saved to the database, it can be used to update the status of a workflow order data instance in an external system, if required.
Workflow Class Method
QorusWorkflow::detach()
Function-Based Detach Logic
It is recommended to use a workflow class to define workflow logic attributes; for old-style function attributes, the signature is as follows:
nothing sub functionname(string status, *string external_order_instanceid) {}

Detach Function Parameters

Type and Name Description
string status The status being set for the workflow order data instance, see Workflow, Segment, and Step Status Descriptions
__7_ string external_order_instanceid The external key for the workflow data being processed, if any exists, otherwise NOTHING
Detach Function Definition Example
# type: GENERIC
# version: 1.0
# desc: example detach function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub example_detach(string stat) {
UserApi::logInfo("detach function: stat=%n", stat);
}
# END
Note
It's recommended to use a workflow class instead of functions for the best forward compatibility with future versions of Qorus

Deprecated Error Handler Function

Synopsis
This code is called when errors are raised. It allows workflows to do external logging or to take custom actions when errors are raised.
Workflow Class Method
QorusWorkflow::errorHandler()
Function-Based Error Handler
It is recommended to use a workflow class to define workflow logic attributes; for old-style function attributes, the signature is as follows:
nothing sub functionname(string errcode, *hash errinfo, any opt) {}

Error Handler Function Parameters

Type and Name Description
string errcode The error code string (ex: "QORE-EXCEPTION")
__7_ hash errinfo This parameter will only be present if the error has been defined by the Deprecated Workflow Error Function; if so, the hash should have at least the following keys (key names in square brackets (i.e. [name]) are optional):
- desc: description of the error
- severity: Error Severity Codes
- status: either OMQ::StatRetry (meaning that the step should be retried) or OMQ::StatError
- [retry-delay]: the delay in seconds before the error should be retried (only valid when status is OMQ::StatRetry)
- [business]: if True, this error represents a business error (rather than a technical error); usually implying that there is a problem with the consistency of the order data
any opt This is an optional parameter that can be supplied by the workflow when an error is raised. Normally it will be a string providing additional information about the error.
Error Handler Function Definition Example
# type: GENERIC
# version: 1.0
# desc: example error handler function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub example_error_handler(string err, *hash hash, any info) {
UserApi::logInfo("error handler: err=%y, hash=%y, info=%y", err, hash, info);
}
# END
Note
It's recommended to use a workflow class instead of functions for the best forward compatibility with future versions of Qorus

Deprecated Workflow Error Function

Synopsis
This function is executed by oload when the workflow is loaded into the database, therefore this function should not depend on runtime features of Qorus. It returns a hash of error information in the format described below. See Workflow Error Handling and Recovery for more information on how this function and its return value are used. See Global and Workflow-Specific Error Definitions for more information about workflow error level logic
Function Template
hash sub functionname() {}
Expected Return Value
A hash where each key is the error string code (ex: "PAYMENT-MESSAGE-TIMEOUT"), and each value is a hash with error information as given in the following description of the keys:
  • desc: the description of the error
  • severity: the severity code; see Error Severity Codes, default: OMQ::ES_Major
  • status: the status code for the step due to this error; either OMQ::StatRetry or OMQ::StatError (default if not present)
  • business: is this a business error? default: False
  • retry-delay: the default retry time for the error as an integer giving seconds (ie 1200 for 20 minutes) or a relative date/time value (i.e. 2D + 12h or P2D12H, both meaning 2 days and 12 hours); the relative date/time value format is normally recommended as it's more readable
  • level: the error level value; see Error Level Type Constants for possible values; default: OMQ::ErrLevelAuto ("AUTO")

    Only the desc key is required. Note:
    • if the "severity" key is not present, the error has a default severity of OMQ::ES_Major ("MAJOR")
    • if the "status" key is not present, the default is OMQ::StatError ("ERROR")
    • if the "level" key is not present, the default is OMQ::ErrLevelAuto ("AUTO")
    • the "retry-delay" key should only be given on errors with status set to OMQ::StatRetry ("RETRY")
Error Function Definition Example
# type: GENERIC
# version: 1.0
# desc: example error definitions
%new-style
%require-types
%strict-args
%enable-all-warnings
hash sub example_errors() {
return (
"EXAMPLE-ERROR-1": (
"desc" : "example error 1",
"status" : OMQ::StatRetry,
"retry-delay" : 45s,
"business" : False,
),
"EXAMPLE-ERROR-2": (
"desc" : "workflow-specific example error 2 (business)",
"status" : OMQ::StatRetry,
"retry-delay" : 2s,
"business" : True,
"level" : OMQ::ErrLevelWorkflow,
),
);
}
# END

Deprecated Step Definitions

In order to define class steps, each step declaration in the workflow definition file must be defined as a hash containing the following attributes:

Step Definition Hash Key Descriptions

Step Key Type Mand.? Description
name string Y The name and optionally the version of the step (i.e.: "step1:1.0")
version string N The version of the step; this key is not required in the step definition if the step's version is given in the step's name (i.e.: "step1:1.0")
desc string N The description of the step; if this key is not present, then the Qorus server will return the description of the primary step code when step information is requested
classname string N The name and optional version (i.e. "MyStep1:1.0") of the step class, providing all the logic for a step. Note that if this key is not given, oload will assume that a function-based step is being defined
classversion string N The version of the step class if not given in the "classname" parameter
queue string N The name of the queue associated with this step (corresponding to the "Message Queue" element in the diagram above). This key is required for asynchronous steps
arraytype string N For array steps, this valid must be "SERIES", in which case the step will be an array step
subworkflow bool N If this is set to True, then the step type attribute will be set to OMQ::ExecSubWorkflow making the step a subworkflow step. Steps may not be simultaneously subworkflow and asynchronous or workflow synchronization event steps
eventtype string N The name of the workflow event type for workflow synchronization event steps; in this case the step may not be a subworkflow or asynchronous step
user-interaction bool N If this is set to True, then the asynchronous step will support APIs for user interaction; can only be set on asynchronous steps; if not present the default value is False
See also
Deprecated Class Definition File for information on how to define the class containing the step's logic
Qore Class-Based Step Configuration Items

Step configuration items are defined in YAML metadata; the programmatic definition of configuration items is deprecated.

Step configuration items in Qore are declared by overriding the QorusConfigurationItemProvider::getConfigItemsImpl() method in the step class. The step configuration items are registerted as part of the basic configuration of the step by oload when the workflow is loaded.

Each ConfigItemInfo hash in the return value of this method defines a configuration item for the step. The value of configuration items can then be retrieved and used in the workflow by calling one of the following APIs.

API Type API Description
Qore WorkflowApi::getConfigItemValue() retrieves a single configuration item value
Qore WorkflowApi::getConfigItemHash() retrieves all configuration items
Qore Step Config Item Declaration Example:
public class ExampleNormalStep inherits QorusNormalStep {
primary() {
logInfo("running %s::primary()", self.className());
}
private *hash<string, hash<ConfigItemInfo>> getConfigItemsImpl() {
return {
"example-string": <ConfigItemInfo>{
"default_value": "example",
"description": "This is an example local configuration item",
"strictly_local": True,
},
"example-int": <ConfigItemInfo>{
"type": "int",
"default_value": 1,
"description": "This is an example configuration item",
},
};
}
}
Note
If the Qore-based workflow depends on a module that defines the configuration items, the workflow must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.
Java Step Class-Based Step Configuration Items

Step configuration items are defined in YAML metadata; the programmatic definition of configuration items is deprecated.

Step configuration items in Java are declared by overriding the QorusStepBase.getConfigItemsImpl() method in the step class. The step configuration items are registerted as part of the basic configuration of the step by oload when the workflow is loaded.

Each ConfigItem object in the return value of this method defines a configuration item for the step. The value of the configuration item can then be retrieved and used in the workflow by calling one of the following APIs.

API Type API Description
Java WorkflowApi.getConfigItemValue() retrieves a single configuration item value
Java WorkflowApi.getConfigItemHash() retrieves all configuration items
Java Step Config Item Declaration Example:
public class MyExampleNormalStepClass extends QorusNormalStep {
public void primary() throws Throwable {
// ... primary step logic
}
protected HashMap<String, ConfigItem> getConfigItemsImpl() {
return new HashMap<String, ConfigItem>() {
{
put("example-string", new ConfigItem("This is an example configuration item").withDefaultValue("test"));
put("example-int", new ConfigItem("This is an example configuration item").withType("int"));
}
};
}
}
Note
If the Java-based service depends on a compiled object that defines the configuration items, the service must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.

Deprecated Class-Based Step User Metadata

Steps can also provide user-defined metadata which is returned as part of the step's description by overriding one of the following methods in the step class:

Note that step metadata is created by oload when the step is loaded, therefore this method should not rely on any runtime features of Qorus that are not available in oload.

Deprecated Function-Based Step Definitions

For backwards compatibility, Qorus supports defining steps with functions defining each logic or code attribute of a step. In order to define complex function-based steps, each step declaration in the workflow definition file must be defined as a hash containing the following attributes:

Step Definition Hash Key Descriptions

Step Key Type Mand.? Description
name string Y The name and optionally the version of the step (i.e.: "step1:1.0")
version string N The version of the step; this key is not required in the step definition if the step's version is given in the step's name (i.e.: "step1:1.0"
desc string N The description of the step; if this key is not present, then the Qorus server will return the description of the primary step code when step information is requested
funcname string N The name and version of the primary step code (corresponding to the "Step Logic" element in the diagram above). Note that if this key is not given, the step function's name and version will be assumed to be the same as the step's (as defined in the name key)
valname string N The name and version of the validation code for the step (corresponding to the "Validation Function" element in the diagram above). The validation code is run whenever the step is recovered. Note that validation code may not be defined for subworkflow or workflow synchronization event steps
endname string N The name and version of the back-end code for asynchronous steps (corresponding to the "Async Logic" element in the diagram above). Note that if this key is defined, a queue must be defined, and the step type attribute will be set to OMQ::ExecAsync. The step may not also be a subworkflow step or a workflow synchronization event step
queue string N The name of the queue associated with this step (corresponding to the "Message Queue" element in the diagram above). This key is required for asynchronous steps
arrayname string N The name and version of the array function (corresponding to the "Array Logic" element in the diagram above). If this key is defined, then the step will be an array step
subworkflow bool N If this is set to True, then the step type attribute will be set to OMQ::ExecSubWorkflow making the step a subworkflow step. Steps may not be simultaneously subworkflow and asynchronous or workflow synchronization event steps
eventtype string N The name of the workflow event type for workflow synchronization event steps; in this case the step may not be a subworkflow or asynchronous step
user-interaction bool N If this is set to True, then the asynchronous step will support APIs for user interaction; can only be set on asynchronous steps; if not present the default value is False
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus

Deprecated Normal Class-Based Step Definition Example

# example step definition
const simple_step = (
"name": "simple_step:1.0",
"classname": "MyNormalStep:1.0",
);
See also
class-based steps

Deprecated Normal Function-Based Step Definition Example

# example step definition
const simple_step = (
"name": "simple_step:1.0",
"valname": "simple_validation:1.0",
);
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
See also
function-based steps

Deprecated Subworkflow Class-Based Step Definition Example

# example step definition
const subworkflow_step = (
"name": "subworkflow_step:1.0",
"classname": "MySubworkflowStep:1.0",
"subworkflow": True,
);
See also
class-based steps

Deprecated Subworkflow Function-Based Step Definition Example

# example step definition
const subworkflow_step = (
"name": "subworkflow_step:1.0",
"subworkflow" : True,
);
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
See also
function-based steps

Deprecated Asynchronous Class-Based Step Definition Example

# example step definition
const async_step = (
"name": "async_step:1.0",
"classname": "MyAsyncStep:1.0",
"queue": "async_queue",
);

Deprecated Asynchronous Function-Based Step Definition Example

# example step definition
const async_step = (
"name": "async_step:1.0",
"valname": "async_validation:1.0",
"endname": "async_backend:1.0",
"queue": "async_queue",
);
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
See also
function-based steps

Deprecated Workflow Synchronization Event Class-Based Step Definition Example

# example step definition
const array_eventtest = (
"name": "array_eventtest:1.0",
"classname": "MyEventStep:1.0",
"eventtype": "event-test",
);
See also
class-based steps

Deprecated Workflow Synchronization Event Function-Based Step Definition Example

# example step definition
const array_eventtest = (
"name": "array_eventtest:1.0",
"eventtype": "event-test",
);
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
See also
function-based steps

Deprecated Array Type attribute

The arraytype attribute may be given in a step definition to ensure that the step is defined as an array step. For class-based steps, this step attribute is mandatory for array steps, and will ensure that one of the above step classes is used as a base class for the step's class.

Example:

# example step definition for a class-based normal array step
const async_array_step = (
"name": "my_step:1.0",
"classname": "MyArrayStep:1.0",
"arraytype": "SERIES",
);

Deprecated Class-Based Array Step Definition Examples

Workflow Definition File Example: Class-Based Asynchronous Array Step
# example step definition for a class-based async array step
const async_array_step = (
"name": "async_array_step:1.0",
"classname": "MyAsyncArrayStep:1.0",
"queue": "async_queue",
"arraytype": "SERIES",
);
Workflow Definition File Example: Class-Based Subworkflow Array Step
# example step definition for a class-based subworkflow array step
const subworkflow_array_step = (
"name": "subworkflow_array_step:1.0",
"classname": "MySubworkflowArrayStep:1.0",
"subworkflow": True,
"arraytype": "SERIES",
);
Workflow Definition File Example: Class-Based Workflow Synchronization Event Array Step
# example step definition for a class-based event step
const array_eventtest = (
"name": "my_event:1.0",
"classname": "MyEventArrayStep:1.0",
"eventtype": "my-event",
"arraytype": "SERIES",
);

Deprecated Function-Based Array Step Definition Examples

Workflow Definition File Example: Function-Based Asynchronous Array Step
# example step definition for a function-based async array step
const async_array_step = (
"name": "async_array_step:1.0",
"valname": "async_array_validation:1.0",
"endname": "async_array_backend:1.0",
"arrayname": "async_array_function:1.0",
"queue": "async_queue",
);
Workflow Definition File Example: Function-Based Subworkflow Array Step
# example step definition for a function-based subworkflow array step
const subworkflow_array_step = (
"name": "subworkflow_array_step:1.0",
"subworkflow": True,
"arrayname": "subworkflow_array_function:1.0",
);
Workflow Definition File Example: Function-Based Workflow Synchronization Event Array Step
# example step definition for a function-based event step
const array_eventtest = (
"name": "my_event:1.0",
"eventtype": "my-event",
"arrayname": "my_event_array:1.0",
);
Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus

Deprecated Primary Step Function

Qorus supports defining functions as step attributes instead of using a class for backwards-compatibility. This section describes defining a primary step function for a step.

Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
Function Template For Non-Array Steps
nothing sub functionname() {}
Function Template Array Steps
nothing sub functionname(auto arrayelement) {}
Note
An argument will be passed to the step function only if the step is an array step (this will be the element corresponding to that position in the array). Otherwise no argument will be passed to the step function.
Expected Return Value
NOTHING (any return value will be ignored)

Example Normal Array Function Definition
# type: STEP
# version: 1.0
# desc: my normal array function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub my_array(auto element) {
UserApi::logInfo("element = %n", element);
}
# END

Example Non-Array Subworkflow Function Definition
# type: SUBWORKFLOW
# version: 2.0
# desc: my subworkflow function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub my_subworkflow() {
# if "skip-subworkflow" is set, skip subworkflow
if (WorkflApi::getPption("skip-subworkflow")) {
wf_skip_subworkflow();
return;
}
# bind to MY-SUBWORKFLOW version 1.0
hash<auto> h = {
"name": "MY-SUBWORKFLOW",
"version": "1.0",
};
# create workflow data
string key = sprintf("%s-%d", WorkflowApi::getStepInfo().name,
WorkflowApi::getWorkflowInstanceData("workflow_instanceid"));
# take the static data for the subworkflow from the "subworkflow" key in
# this order's static data
hash<auto> data.staticdata = WorkflowApi::getStaticData().subworkflow;
hash<auto> r = wf_bind_subworkflow(h, data);
UserApi::logInfo("subworkflow created, workflow_instance_id=%d", r.workflow_instanceid);
}
# END

Example Non-Array Workflow Synchronization Event Function Definition
# type: STEP
# version: 1.0
# name: my_event
# desc: my event step function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub my_event() {
# sip the event if the "skip-event" option is set
if (WorkflowApi::getOption("skip-event") {
wf_skip_event();
return;
}
# get an event from my event service
string event = omqservice.user.myevent.get();
wf_bind_event(event);
}
# END

see $OMQ_DIR/examples/user/TEST-WORKFLOWS/test-functions-v1.0.qfd for further example function definitions for all function types in this section.

Deprecated Validation Step Function

Qorus supports defining functions as step attributes instead of using a class for backwards-compatibility. This section describes defining a validation function for a step.

Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
Function Template For Non-Asynchronous Non-Array Steps
string sub functionname() {}
Function Template For Non-Asynchronous Array Steps
string sub functionname(auto array_element) {}
Function Template For Asynchronous Array Steps
string sub functionname(*string async_key, auto array_element) {}
Function Template For Asynchronous Non-Array Steps
string sub functionname(*string async_key) {}
Expected Return Value
string: step status constant

Example Asynchronous Validation Function
# type: VALIDATION
# version: 1.0
# desc: my aysnc validation function
%new-style
%require-types
%strict-args
%enable-all-warnings
string sub my_async_validation(*string key) {
# call check_action() to check in the target DB if the action has completed
if (check_action())
return OMQ::StatComplete;
# call check_pending() to see if we retry or still wait
return check_pending() ? OMQ::StatAsyncWaiting : OMQ::StatRetry;
}
# END

Deprecated Asynchronous Back-End Step Function

Qorus supports defining functions as step attributes instead of using a class for backwards-compatibility. This section describes defining a asynchronous back-end function for a step.

Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
Non-Array Backend Function Template
nothing sub functionname(auto queue_data) {}
Array Backend Function Template
nothing sub functionname(auto queue_data, auto array_element) {}
Note
The array_element argument will be passed to the back end function only if the step is an array step. Otherwise only the queue_data argument will be passed to the function; the queue_data argument is the data that is posted on the queue when with the POST /api/latest/async-queues/{queue}?action=update call when the queue is updated.
Expected Return Value
NOTHING (any return value will be ignored)

Example back-end code
# type: ASYNC-END
# version: 1.0
# desc: my async back end function
%new-style
%require-types
%strict-args
%enable-all-warnings
sub my_async_end(hash<auto> data) {
# the error thrown here should be defined as a workflow error
if (data.status == "ERROR") {
throw "ASYNC-RECEIVE-ERROR";
} else {
UserApi::logInfo("data status: %y", data.status);
}
}
# END

Deprecated Queue Tag

Synopsis
The queue tag must be set to a string giving the name of the queue for asynchronous steps. The queue will link the asynchronous step's primary step code with the back-end code.

When the result of the asynchronous action is available, the result must be posted to the step's queue using the key created in the step's primary step code when the QorusAsyncStepBase::submitAsyncKey() method (for class-based steps) is called. The queue will hold this data (stored in the database table QUEUE_DATA) and pass it to the asynchronous back-end code in order to determine the step's status.

See Deprecated Queue Definitions for more information.

Deprecated Array Function

Qorus supports defining functions as step attributes instead of using a class for backwards-compatibility. This section describes defining a asynchronous back-end function for a step.

Note
It's recommended to use class-based steps for the best forward compatibility with future versions of Qorus
Function Template
any sub functionname() {}
Possible Return Values
list: List of elements for array step; if the list is empty, then the array step is skipped
any: A single element to execute a single substep in the array step
nothing: if NOTHING is returned, then the array step is skipped

Example of Array Function Definition
# type: ARRAY
# version: 1.0
# desc: my array function
%new-style
%require-types
%strict-args
%enable-all-warnings
*list sub my_array() {
# returns the list under the AccountInfoList key in static data
return WorkflowApi::getStaticData().AccountInfoList;
}
# END

Deprecated Subworkflow Tag (subworkflow)

Synopsis
If this boolean tag is set to True, then the step will be a subworkflow step, and the step's status will be bound to a new workflow (the subworkflow) when the QorusSubworkflowStepBase::bindSubworkflow() method (for class-based steps) or Qorus DataProvider API: Bind Subworkflow is called. If neither this method nor QorusSubworkflowStepBase::skipSubworkflow() (for class-based steps) or Qorus DataProvider API: Skip Subworkflow is called, then the step will exit with an error. Otherwise, if a subworkflow is bound, the step will receive a WAITING status until the subworkflow is COMPLETE or ERROR, at which time the step will be updated with the subworkflow's status.
See also
Subworkflow Step for an example of a subworkflow step definition where this key is set to True
Note: Use a Subworkflow Step for Logical Branching
Each step in a Qorus workflow is executed and must receive a COMPLETE status in order for the workflow to become COMPLETE. If there is a series of steps that is only conditionally executed, bind it to a subworkflow step and create a workflow that will be bound to that step.

Deprecated Event Type Tag (eventtype)

Synopsis
If this string tag is present, then the step will be a workflow synchronization event step, and the step must either be bound to a workflow synchronization event by calling QorusEventStepBase::bindEvent() / Qorus DataProvider API: Bind Workflow Synchronization Event or QorusEventStepBase::bindEventUnposted() / Qorus DataProvider API: Bind Workflow Synchronization Event Unposted (in class-based steps), or skipped by calling QorusEventStepBase::skipEvent() / Qorus DataProvider API: Skip Workflow Synchronization Event Step (in class-based steps) in the step's primary step code. If none of these APIs are called in the step's primary step code, the step will exit with an error. Otherwise, if a workflow synchronization event is bound to the step, the step will only receive a COMPLETE status when the event is posted by calling Qorus DataProvider API: Post Synchronization Event, UserApi::postSyncEvent(), PUT /api/latest/sync-events/{type}/{key}?action=post, or omq.system.post-event().

The value of the tag must be the name of a valid workflow synchronization event.
See also
Workflow Synchronization Event Steps for an example of a workflow synchronization step definition where this key is defined.

Deprecated Function Definition File

Qorus function definition files should have the extension: *.qfd

Function definition files are used to create function objects in the Qorus schema that can then be used by workflows (or loaded into service program objects as well for GENERIC functions).

Functions are defined by adding metadata tags in the form of special line comments to normal text files containing function definitions. The tags are parsed by the oload program, which will create function objects in the Qorus database according to the definitions in the file.

Function definitions begin with metadata tags as given in as specially-formatted comments as seen in the example below. After the header tags, one or more function definitions then follow, and the END tag terminates the function definition.

Function Definition File Tags

Tag Mand.? Description
type Y must be the first tag in a function definition, value must be one of the Step Function Types
name N If the name tag is not defined, then the name of the function object in the database will be taken from the last function defined in the code block. If the name tag is defined, then a function with this name generally must be defined in the code block when used as a step function, however when used as a library function the name of the function object does not have to correspond to any function in the code block
version Y Version string for the function object
desc Y Description of the function object
author N The optional author of the code object
patch N Optional patch string – should be updated every time the same version of the function object is updated in the database
TAG N Option tag definition in the format "key: value"
END Y This tag must be included to terminate the function definition
Note
A single function object can contain more than one function definition, but must contain at least one function definition with the same name as the object, unless if the function object will be used as a library function, then the name of the function object does not have to correspond to any function in the code block.
Example Function Definitions
Here is an example function definition with the minimum required tags:
# type: GENERIC
# version: 1.0
# desc: example function for the Qorus Developer's Guide
# TAG: example-code: true
%new-style
%require-types
%strict-args
%enable-all-warnings
sub example_func() {
log(OMQ::LL_INFO, "the example function is here");
}
# END

Here are further examples:

Deprecated Class Definition File

Qorus class definition files should have the extension: *.qclass or *.qclass.java (for Java-based classes).

Class definition files are used to create class objects in the Qorus schema that can then be used by workflows (or loaded into service program objects as well).

Like function objects, classes are defined by adding metadata tags in the form of special comments to normal text files containing class definitions. The tags are parsed by the oload program, which will create class objects in the Qorus database according to the definitions in the file.

Class definitions begin with metadata tags as given in as specially-formatted comments as seen in the examples below. After the header tags, one or more class definitions then follow, and the END tag terminates the class definition.

Class Definition File Tags

Key Mand.? Description
name N If the name tag is not defined, then the name of the class object will be taken from the last class defined in the code block. If the name tag is defined, then a class with this name should normally be defined in the code block, but the current version of Qorus does not enforce this
version Y Version string for the class object
desc Y Description of the class object
author N The optional author of the code object
patch N Optional patch string – should be updated every time the same version of the class object is updated in the database
lang N the possible values are "qore" for Qore code (the default) and "java" for code targeting the Java 8 JVM (see Developing in Java)
requires N Optional list of classes required by the current class; causes the required classes to be loaded when the current class is loaded
TAG N Option tag definition in the format "key: value"; for Java classes, entries in the classpath can be added here by adding a colon-separated list of path names to the "classpath" tag; note also that $OMQ_DIR (or any other server-side environment variable) can be used in classpath entries and will be resolved to the Qorus directory
END Y This tag must be included to terminate the class definition
Example Qore Class Object Definition (QoreExampleClass-v1.0.qclass)
# name: QoreExampleClass
# version: 1.0
# desc: example class for the Qorus Developer's Guide
# patch: p1
# TAG: example-code: true
%new-style
%require-types
%strict-args
%enable-all-warnings
class QoreExampleClass {
constructor() {
UserApi::logInfo("QoreExampleClass::constructor() here");
}
}
# END

Example Java Class Object Definition (JavaExampleClass-v1.0.qclass.java)
// name: JavaExampleClass
// version: 1.0
// desc: example class for the Qorus Developer's Guide
// patch: p1
// lang: java
// TAG: example-code: true
// TAG: classpath: $OMQ_DIR/user/jar/my-jar-1.jar:$OMQ_DIR/user/jar/my-jar-2.jar
package org.example;
import com.qoretechnologies.qorus.UserApi;
// import MyClass from my-jar.jar
import org.example.MyClass;
// inherit UserApi so static members and methods can be used without a class prefix
class JavaExampleClass extends UserApi {
JavaExampleClass() throws Throwable {
logInfo("JavaExampleClass constructor() here");
}
}
// END

Note
  • A single class Qore object definition can contain more than one class definition, but by convention should normally contain at least one class with the same name as the object.
  • Java class definitions must contain only one class, and the class defined must correspond to the name or Java compilation will fail
  • The classpath tag can be used to add entries to the classpath for Java classes; $OMQ_DIR can be used in classpath entries as in the above example and will be resolved to the Qorus directory; see Java Classpath Handling in Qorus for more information

See the classes listed in Step Source Class Definitions for example class definitions for class-based steps

Deprecated Constant Definition File

Qorus constant definition files should have the extension: *.qconst

Constant definition files are used to create constant objects in the Qorus schema that can then be used by workflows (or loaded into service program objects).

Like function and class objects, constant objects are defined by adding metadata tags in the form of special comments to normal text files containing constant definitions. The tags are parsed by the oload program, which will create constant objects in the Qorus database according to the definitions in the file.

Constant definitions begin with metadata tags as given in as specially-formatted comments as seen in the example below. After the header tags, one or more constant definitions then follow, and the END tag terminates the constant definition.

Constant Definition File Tags

Key Mand.? Description
name Y The name tag must be defined for constant objects
version Y Version string for the constant object
desc Y Description of the constant object
author N The optional author of the code object
patch N Optional patch string – should be updated every time the same version of the constant object is updated in the database
TAG N Option tag definition in the format "key: value"
END Y This tag must be included to terminate the constant definition
Example Constant Object Definition
# name: exampleConstant
# version: 1.0
# desc: example constant for Qorus Developer's Guide
# patch: p1
# TAG: example-code: true
%new-style
%require-types
%strict-args
%enable-all-warnings
namespace Test {
const this = 1;
const that = "two";
}
# END

Deprecated Service Definition File

Qorus service definition files have the extension: *.qsd or *.qsd.java for Java services.

Service definition files are used to create service objects in the Qorus schema that can then be loaded and their methods can be called from any Qorus code, and, for external methods, from external applications through lightweight web-service protocols exported through the HTTP server as well.

Services are defined by adding metadata tags in the form of specially-formatted comments to normal text files containing at least one service definition and at least one method definition for the service. The tags are parsed by the oload program, which will create the service objects in the Qorus database according to the definitions in the file.

The first part of the file should contain the definitions for the service metadata. Service metadata definitions are entirely comprised of metadata tags as shown in the example below; the ENDSERVICE tag terminates the service metadata definition.

Service Metadata Definition File Tags

Key Mand.? Description
service Y The name of the service
serviceversion Y Version string for the service object.
servicedesc Y Description of the service object.
serviceauthor N The optional author of the code object
class-based N Set to true to define a class-based service (recommended); if not set or false, a function-based service will be assumed (only supported for backwards compatibility)
class-name N Set this to the class name of the service's class in case it differs from the service name; this allows the service to have names that are not valid identifiers in the source language (Qore or Java); implies class-based: true
service-modules N lists modules providing base classes for class-based services
remote N The optional remote status of the service, indicating if the service will run in an independent qsvc process (always False for system services; see qorus-client.remote for how the default value is set by oload when loading user services)
autostart N The value of the autostart property of the service (default: False, managed by operations)
lang N the possible values are "qore" for Qore code (the default) and "java" for code targeting the Java 8 JVM (see Developing in Java); note that lang: java implies class-based: true (see class-based services)
classes N An optional list of class objects to load into the service program object
constants N An optional list of constant objects to load into the service program object
functions N An optional list of functions to load into the service program object
mappers N An optional list of mappers to register with the service so they are available with the UserApi::getMapper() call
vmaps N An optional list of value maps to register with the service so they can be used with the UserApi::getValueMap() call
patch N Optional patch string; does not affect version compatibility; this value should be updated every time the same version of the service object is updated in the database.
parse-options N Comma-separated parse options for the service: one of OMQ::ServiceParseOptionList; this is applied to all methods and also any service resource template programs
define-auth-label N defines an authentication label with an associated value in the format label=value
define-group N Allows Interface Groups to be defined; format is: name: description; see below for an example
groups N one or more Interface Groups that the service is a member of
resource N each resource line describes one or more files (if wildcards are used) that will be loaded into the database as service file resources for use in serivces that provide HTML UI services; using this tag the resource type will be derived from the file name (either "text", "binary", or "template")
text-resource N defines text file resources (accepts wildcards)
bin-resource N defines binary file resources (accepts wildcards)
template N defines template file resources (accepts wildcards)
TAG N Option tag definition in the format "key: value"; for Java services, entries in the classpath can be added here by adding a colon-separated list of path names to the "classpath" tag; note also that $OMQ_DIR (or any other server-side environment variable) can be used in classpath entries and will be resolved to the Qorus directory
ENDSERVICE Y This tag must be included to terminate the service metadata definition.
Note
  • Java service definitions must contain only one service
  • The classpath tag can be used to add entries to the classpath for Java services; $OMQ_DIR can be used in classpath entries as in the above example and will be resolved to the Qorus directory; see Java Classpath Handling in Qorus for more information

Deprecated Class-Based Service Definitions

Example Qore Class-Based Service Definition: my-service-v1.0.qsd
# service: my-service
# serviceversion: 1.0
# patch: p1
# class-name: MyService
# remote: true
# servicedesc: example service
# class-based: true
# classes: exampleClass1, exampleClass2
# constants: exampleConstant1, exampleConstant2
# functions: exampleFunction
# define-group: EXAMPLES: example interface objects
# groups: EXAMPLES
# parse-options: PO_NEW_STYLE, PO_STRICT_ARGS, PO_REQUIRE_TYPES
# TAG: example-code: true
# ENDSERVICE
class MyService inherits QorusService {
public {
static date systemStarted;
}
# this class method cannot be exported as a service method
constructor() {
# initialization of this variable is performed in the constructor so oload will not fail when the
# class is initialized in oload
systemStarted = callRestApi("GET", "system/starttime");
}
# name: init
# desc: initializes the service
init() {
}
# name: other
# desc: an example static service method
static other() {
}
}
Example Java Service Definition: my-java-service-v1.0.qsd.java
// service: my-java-service
// serviceversion: 1.0
// patch: p1
// lang: java
// class-name: MyJavaService
// remote: true
// servicedesc: example service
// define-group: EXAMPLES: example interface objects
// groups: EXAMPLES
// TAG: example-code: true
// ENDSERVICE
package com.qoretechnologies.qorus.example;
import com.qoretechnologies.qorus.UserApi;
import com.qoretechnologies.qorus.service.*;
import java.time.ZonedDateTime;
class MyJavaService extends QorusService {
public static final ZonedDateTime systemStarted;
static {
try {
systemStarted = (ZonedDateTime)callRestApi("GET", "system/starttime");
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@QorusMethod(
desc = "initializes the service"
)
public void init() {
}
@QorusMethod(
desc = "an example static service method"
)
public static void other() {
}
}

Deprecated Qore Class-Based Service Configuration Items

Service configuration items are declared in Qore by overriding the QorusConfigurationItemProvider::getConfigItemsImpl() method in the service class. The service configuration items are registerted as part of the basic configuration of the service by oload when the service is loaded.

Each ConfigItemInfo hash in the return value of this method defines a configuration item for the service. The value of configuration items can then be retrieved and used in the service by calling one of the following APIs.

API Type API Description
Qore ServiceApi::getConfigItemValue() retrieves a single configuration item value
Qore ServiceApi::getConfigItemHash() retrieves all configuration items
Qore Service Config Item Declaration Example:
public class TestService inherits QorusService {
# name: example
# desc: method defined in the TestService module
string example() {
return "example";
}
private *hash<string, hash<ConfigItemInfo>> getConfigItemsImpl() {
return {
"example-string": <ConfigItemInfo>{
"default_value": "example",
"description": "This is an example configuration item",
},
"example-int": <ConfigItemInfo>{
"type": "int",
"default_value": 1,
"description": "This is an example configuration item",
},
};
}
}
Note
If the Qore-based service depends on a module that defines the configuration items, the service must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.

Deprecated Java Class-Based Service Configuration Items

Step configuration items in Java are declared by overriding the QorusService.getConfigItemsImpl() method in the service class. Service configuration items are registerted as part of the basic configuration of the service by oload when the service is loaded.

Each ConfigItem object in the return value of this method defines a configuration item for the service. The value of the configuration item can then be retrieved and used in the service by calling one of the following APIs.

API Type API Description
Java ServiceApi.getConfigItemValue() retrieves a single configuration item value
Java ServiceApi.getConfigItemHash() retrieves all configuration items
Java Service Config Item Declaration Example:
public class JavaServiceExample extends QorusService {
@QorusMethod(
desc = "example method",
author = "Qore Technologies, s.r.o.",
lock = LockType.None,
write = false,
intern = false
)
public static String example() {
return "example method";
}
protected HashMap<String, ConfigItem> getConfigItemsImpl() {
return new HashMap<String, ConfigItem>() {
{
put("example-string", new ConfigItem("This is an example configuration item").withDefaultValue("test"));
put("example-int", new ConfigItem("This is an example configuration item").withType("int").withMandatoryDefault(1));
}
};
}
}
Note
If the Java-based service depends on a compiled object that defines the configuration items, the service must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.

Deprecated Function-Based Services

Function-based services are supported for backwards compatibility; a function-based service's methods are defined by functions.

Example Qore Function-Based Service Definition
# service: example_service
# serviceversion: 1.0
# patch: p1
# remote: true
# servicedesc: example service
# classes: exampleClass1, exampleClass2
# constants: exampleConstant1, exampleConstant2
# functions: exampleFunction
# define-group: EXAMPLES: example interface objects
# groups: EXAMPLES
# parse-options: PO_NEW_STYLE, PO_STRICT_ARGS, PO_REQUIRE_TYPES
# TAG: example-code: true
# ENDSERVICE

Method definitions following the service metadata definition, also using tags to define the method metadata for the oload program. The END tag terminates the method definition.

Service Method Definition Tags

Key Mand.? Description
lock N must be either none, read, or write (default none), to determine how the service's RWLock will be grabbed before the method is executed
name N If the name tag is not defined, then the name of the method will be taken from the first function defined in the code block. If the name tag is defined, then a function with this name must be defined in the code block (name tags are optional for function-based service methods)
desc Y Description of the method object
author N The optional author of the code object
internal N If this boolean flag is set to True, then the method will not be automatically exported through the any network interface
write N If this boolean flag is set to True, then the method will be marked as a write method, meaning that external callers will have to have the CALL-USER-SERVICES-RW role to call the method if RBAC security is enabled (Enterprise Edition only)
END Y This tag must be included with function-based services to terminate the method definition
Example Function-Based Service Method Definition
# lock: none
# name: exampleMethod
# desc: example method for Qorus Developer's Guide
# internal: false
# write: false
sub exampleMethod(int arg){
return arg + 1;
}
# END
Note
A single method definition can contain more than one function definition, but must contain at least one function definition with the same name as the method.

Deprecated Service Authentication Labels

Note
Service authentication labels are deprecated; use config items instead to control service authentication handling.

Service authentication labels allow for the authentication method for a service to be changed at runtime with the UI or the API by an authorized user.

Authentication labels are unique to a service; if the value of an authentication label is changed for a specific service, it does not affect any authentication label with the same name for another service.

Authentication labels are used by the QorusParametrizedAuthenticator class.

Authentication labels are defined with an authentication label name and one of the following values:

  • "permissive": allows all requests to succeed
  • "default": uses default Qorus authentication
  • "default-basic": uses default Qorus authentication and returns the WWW-Authenticate header with 401 Unauthorized responses to ensure that web browsers will request a username and password for basic authentication in the next request.
Note
Service authentication labels are considered to be managed by operations, which means that once a service has been loaded into Qorus, if its authentication label is updated with the API, then those API-driven changes are persistent and will not be overwritten by subsequent loads of the service by oload.
See also
QorusParametrizedAuthenticator

Deprecated Job Definition Files

Qorus job definition files should have the extension *.qjob or *.qjob.java for Java-based jobs to identify the file's contents properly to the schema loader.

Jobs are defined by adding metadata tags in the form of specially-formatted comments to normal text files containing at least one complete job definition. The tags are parsed by the oload program, which will create the jobs in the Qorus database according to the information in the file.

The file consists of tags defining the job and then the code that makes up the job. At the end of the source code, the END tag terminates the job definition.

Job Definition File Tags

Key Mand.? Description
name Y The name of the job
version Y Version string for the job object; this version is informative; only one version of a job is stored in the database at a time
desc Y Description of the job object
author N The optional author of the code object
job-modules N lists modules providing base classes for class-based jobs
remote N The optional remote status of the job, indicating if the job will run in an independent qjob process (see qorus-client.remote for how the default value is assigned by oload)
active N A boolean value giving the active status of the job; if not present, the default is True
run-skipped N A boolean value telling the system if the job should be run immediately if the last scheduled run was missed due to system downtime; if not present, the default is True
duration * a schedule duration in seconds; if present the job will be scheduled to run every n seconds where n is the value assigned to this tag; either this tag or the schedule tag must be present, but not both
schedule * a cron specification, see Job Schedule for more information; either this tag or the duration tag must be present, but not both
expiry-date N An optional expiration date; the job will not be run (and will be automatically set to inactive) when the expiration date is reached
class-based N Set to true to define a class-based job (recommended); if not set or false, a function-based job will be assumed (only supported for backwards compatibility)
class-name N Set this to the class name of the job's class in case it differs; this allows the job to have names that are not valid identifiers in the source language (Qore or Java)
lang N the possible values are "qore" for Qore code (the default) and "java" for code targeting the Java 8 JVM (see Developing in Java)
classes N An optional list of class objects to load into the job program object
constants N An optional list of constant objects to load into the job program object
functions N An optional list of functions to load into the job program object
mappers N An optional list of mappers to register with the job so they are available with the UserApi::getMapper() call
vmaps N An optional list of value maps to register with the job so they can be used with the UserApi::getValueMap() call
define-group N Allows Interface Groups to be defined; format is: name: description; see below for an example
groups N one or more Interface Groups separated by commas that the job is a member of
TAG N Option tag definition in the format "key: value"
END Y This tag must be present after the job's source code to terminate the job definition

The job's code should follow the metadata tags given above.

Note that the logic for the job is defined by either a job class (recommended) or a function (supported for backwards compatibility).

Class-Based Jobs

The recommended way to define a job is by setting the class-based option to true and defining the job's logic as a subclass of one of the following classes depending on the source language:

Example Qore Class-Based Job Definition: example-job-v1.0.qjob:
# name: example-job
# version: 1.0
# desc: test job, run every 10 minutes every hour, every weekday
# schedule: */10 * * * mon-fri
# active: true
# run-skipped: true
# define-group: EXAMPLES: example interface objects
# groups: EXAMPLES
# classname: MyExampleJob
# class-based: true
# TAG: example-code: true
%new-style
%require-types
%strict-args
%enable-all-warnings
class MyExampleJob inherits QorusJob {
# the run() method implements the job's logic
run() {
logInfo("job info: %y", getInfo());
}
}
# END
Example Java Class-Based Job Definition: java-example-job-v1.0.qjob.java
// name: java-example-job
// version: 1.0
// desc: test job, run every 10 minutes every hour, every weekday
// author: Qore Technologies, s.r.o.
// class-name: MyJavaExampleJob
// active: true
// run-skipped: true
// schedule: */10 * * * mon-fri
// define-group: EXAMPLES: example interface objects
// groups: EXAMPLES
// lang: java
// TAG: classpath: $OMQ_DIR/user/jar/my-jar-1.jar:$OMQ_DIR/user/jar/my-jar-2.jar
package com.qoretechnologies.qorus.example;
import com.qoretechnologies.qorus.job.QorusJob;
class MyJavaExampleJob extends QorusJob {
// the run method implments the job's logic
public void run() throws Throwable {
logInfo("test job info: %y", getInfo());
}
}
// END
Note
  • Jobs implemented in Java default to class-based = true; see QorusJob for more information and an example Java job definition
  • The classpath tag can be used to add entries to the classpath for Java classes; $OMQ_DIR can be used in classpath entries as in the above example and will be resolved to the Qorus directory; see Java Classpath Handling in Qorus for more information

Deprecated Job Modules

The "job-modules" option lists modules providing base classes for Class-Based Jobs as in the following example.

Example:
# name: example-job
# ...
# job-modules: MyJobModule1, MyJobModule2
# ...

Modules declared like this will be loaded into each jobs's Program object, and their classes can be used as base classes for a job class.

See also
Qore-Language Job Extension Modules for more information.

Deprecated Qore Class-Based Job Configuration Items

Job configuration items are declared in Qore by overriding the QorusConfigurationItemProvider::getConfigItemsImpl() method in the job class. The job configuration items are registerted as part of the basic configuration of the job by oload when the job is loaded.

Each ConfigItemInfo hash in the return value of this method defines a configuration item for the job. The value of the configuration item can then be retrieved and used in the job by calling one of the following APIs.

API Type API Description
Qore JobApi::getConfigItemValue() retrieves a single configuration item value
Qore JobApi::getConfigItemHash() retrieves all configuration items
Qore Job Config Item Declaration Example:
public class TestJob inherits QorusJob {
run() {
logInfo("run method here");
}
private *hash<string, hash<ConfigItemInfo>> getConfigItemsImpl() {
return {
"example-string": <ConfigItemInfo>{
"default_value": "example",
"description": "This is an example configuration item",
},
"example-int": <ConfigItemInfo>{
"type": "int",
"default_value": 1,
"description": "This is an example configuration item",
},
};
}
}
Note
If the Qore-based job depends on a module that defines the configuration items, the job must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.

Deprecated Java Class-Based Job Configuration Items

Step configuration items in Java are declared by overriding the QorusJob.getConfigItemsImpl() method in the job class. Job configuration items are registerted as part of the basic configuration of the job by oload when the job is loaded.

Each ConfigItem object in the return value of this method defines a configuration item for the job. The value of the configuration item can then be retrieved and used in the job by calling one of the following APIs.

API Type API Description
Java JobApi.getConfigItemValue() retrieves a single configuration item value
Java JobApi.getConfigItemHash() retrieves all configuration items
Java Job Config Item Declaration Example:
class JavaExampleJob extends QorusJob {
public void run() throws Throwable {
logInfo("example job info: %y", getInfo());
}
protected HashMap<String, ConfigItem> getConfigItemsImpl() {
return new HashMap<String, ConfigItem>() {
{
put("example-string", new ConfigItem("This is an example configuration item").withDefaultValue("test"));
put("example-int", new ConfigItem("This is an example configuration item").withType("int"));
}
};
}
}
Note
If the Java-based service depends on a compiled object that defines the configuration items, the service must be loaded with oload for the configuration items or changes to the configuration items to take effect; only oload reads the configuration items; changes to configuration items are not detected at runtime.

Deprecated Function-Based Jobs

Function-based jobs are supported for backwards compatibility; a function-based job must have a run() function. This function will be called when the job is scheduled. Note that only active jobs that are not members of any disabled Interface Groups will be scheduled and run.

The job's code also has the job api at its disposal.

Example Function-Based Job Definition
# name: test
# version: 1.0
# desc: test job, run every 10 minutes every hour, every weekday
# schedule: */10 * * * mon-fri
# active: true
# run-skipped: true
# define-group: EXAMPLES: example interface objects
# groups: EXAMPLES
# TAG: example-code: true
# functions: test_job_1
%new-style
%require-types
%strict-args
%enable-all-warnings
sub run() {
UserApi::logInfo("job info: %y", JobApi::getInfo());
test_job_1();
}
# END
Note
  • A job definition can any kind of code that can be parsed with the job's sandboxing restrictions, however at least one function called run() must be present in function-based jobs.
  • Function-based jobs are supported for backwards compatibility, it is recommended to implement class-based jobs instead.

Whenever a job is executed, a record in the JOB_INSTANCE table is created. If an error is raised by calling JobApi::err() with a severity greater than OMQ::ES_Warning, the job instance will get a status of OMQ::JS_Error, otherwise the job instance will get a status of OMQ::JS_Complete. In the case that the Qorus system crashes while the job has a OMQ::JS_InProgress status, then, when the system is recovered, the JOB_INSTANCE row will get a OMQ::JS_Crash status.

Job instances can never be recovered; the status is saved for information purposes only.

To save information about processing status, call the JobApi::saveInfo() method.

The UserApi::log() method is used to save information in the job's log file; see System, Service, Workflow, and Job Logging for more information about log file locations and file formats.

Deprecated Mapper Files

Mappers are defined by adding metadata tags in the form of specially-formatted comments to normal text files containing a complete mapper definition. The tags are parsed by oload, which will create the mappers in the Qorus database according to the information in the file.

The file consists of tags defining the mapper and then option and field definitions. At the end of the mapper definition, the END tag terminates the mapper.

Mapper Definition File Tags

Key Mand.? Description
name Y The name of the mapper
version Y Version string for the mapper object; multiple versions of the same mapper can exist in the database and interfaces (workflows, services, and jobs) must refer to the mapper using its explicit version
patch N A descriptive patchlevel attribute that does not affect version compatibility
desc Y Description of the mapper object
author N The optional author of the mapper object
parse_options N A comma separated list of local parse options for the mapper code; one or more of (options must be given as shown without any namespace prefixes):
- PO_REQUIRE_TYPES
- PO_REQUIRE_PROTOTYPES
- PO_STRICT_ARGS
- PO_ASSUME_LOCAL
- PO_ALLOW_BARE_REFS
type Y The type of mapper; must be a system type or a type provided by a mapper module
classes N An optional list of class objects to load into the mapper program object (subject to %lockdown sandboxing restrictions; see Deprecated Mapper Library Objects for more information)
constants N An optional list of constant objects to load into the mapper program object (subject to %lockdown sandboxing restrictions; see Deprecated Mapper Library Objects for more information)
functions N An optional list of functions to load into the mapper program object (subject to %lockdown sandboxing restrictions; see Deprecated Mapper Library Objects for more information)
define-group N Allows interface groups to be defined; format is: name: description; see below for an example
groups N one or more interface groups that the mapper is a member of for access purposes (mappers cannot be enabled or disabled)

Mapper example:

# name: my-example-table-mapper
# version: 1.0
# desc: Example table mapper for documentation
# mappertype: InboundTableMapper
# author: Joesephine Programmer (Qore Technologies, s.r.o.)
# functions: my-mapper-lib
# parse-options: PO_NEW_STYLE, PO_STRICT_ARGS, PO_REQUIRE_TYPES
# define-group: EXAMPLES: example interface objects
# groups: EXAMPLES
OPTION: datasource: "omquser"
OPTION: table: "example_table"
OPTION: input: (
"order_id": "unique order ID",
"cust_id": "customer ID",
"dealer_id": "dealer ID",
"ordered_quantity": "product quantity",
"product_id": "product ID",
"order_date": "the date and time the order was made",
)
# id is populated from the sequence "example_table_s" in the target datasource
FIELD: id: ("sequence": "example_table_s")
FIELD: source_system: ("constant": "ORDERS")
# note that comments are preserved but ignored
FIELD: order_number: ("name": "order_id")
# order_code is populated according to a closure combining the cust_id and order_id values into a single string
FIELD: order_code: ("code": string sub (auto ignored, hash rec) {
return sprintf("%s-%s", rec.cust_id, rec.order_id);
},
)
FIELD: customer_number: ("name": "customer_id")
FIELD: dealer_code: ("name": "dealer_id")
FIELD: product_code: ("name": "product_id")
FIELD: qty: ("name": "ordered_quantity")
FIELD: ordered_date: ("name": "order_date")
# created_date is populated with the current date and time when the row is inserted
FIELD: created_date: ("code": date sub (auto ignored, hash rec) { return now_us(); })
Note
in the above example, the "output" option is not defined since it's defined automatically by the InboundTableMapper mapper type

Deprecated Mapper Types

The following mapper types are provided by the system:

Additional mapper types can be provided by implementing a mapper module; see Deprecated Mapper Module Developent for more information.

Deprecated Mapper Options

Common options for all mappers are defined by the Mapper class here: Mapper Options, but each mapper type can extend this list with its own options, some of which may be required as well.

Mappers object must provide the input and output options by default, but these may be generated automatically by the particular mapper type (for example, the OMQ::InboundTableMapperType class automatically generates the output option based on the target table); see the mapper type documentation for more information.

Mapper input options are specified with the following syntax:

  • OPTION: option_name: expression

Where:

  • option_name: is the name of the option; this must be an option supported by the mapper. Note that all mappers inherit Mapper::Mapper, therefore all mappers support at least the options defined here: Mapper Options. Additionally, mappers must define the input and output options, but these may be defined automatically by the mapper type itself; see the documentation for the particular mapper type for more information
  • expression: is a Qore expression that will be executed to give the value of the mapper option

See the example in the preceding section.

Deprecated Mapper Input Option

This option is a hash that describes the input data structures; see the "input" key of Mapper Options for more information.

Note that only input field names defined as keys in this hash can be used as input field names in mapper field definitions.

While all mapper ojects generated by a mapper type must define the "input" and "output" keys, mapper types may define these automatically (for example, the OMQ::InboundTableMapperType class automatically generates the output option based on the target table); see the mapper type documentation for more information.

Deprecated Mapper Output Option

This option is a hash that describes the output data structures; see the "output" key of Mapper Options for more information.

Note that only output field names defined as keys in this hash can be used as Deprecated Mapper Fields.

While all mapper ojects generated by a mapper type must define the "input" and "output" keys, mapper types may define these automatically (for example, the OMQ::InboundTableMapperType class automatically generates the output option based on the target table); see the mapper type documentation for more information.

Deprecated Mapper Fields

Mapper field transformations are based on Mapper Specification Format and are specified with the following syntax:

  • FIELD: output_field: expression

Where:

  • output_field: is the name of the output field; this must be also defined by the output option (either explicitly in the mapper definition or implicitly by the mapper type)
  • expression: is a Qore expression describing how the output is generated; for possible values, see Mapper Specification Format

All Qorus mapper field descriptions support the following two additional keys which are added at runtime to all mapper:

  • "context": any string value assigned to this key will be used as the argument to UserApi::expandTemplatedValue(); the return value of this method call will be used as the value of the field
  • "template": if assigned to True; the value of the field will be passed as the sole argument to UserApi::expandTemplatedValue(); the return value of this method call will be used as the value of the field

Deprecated Mapper Library Objects

Mappers support library objects in way similar to workflows, services, and jobs, however mapper library objects are subject to %lockdown sandboxing restrictions, so every library object imported into a mapper Program object must meet this criterion or it cannot be used in a mapper.

%lockdown prohibts any I/O; also logging is not allowed from within a mapper, so generally library code used elsewhere in Qorus workflows, services, and jobs is not suitable for use in a mapper.

Mapper library objects can be used in workflows, services, and jobs however.

Deprecated Mapper Module Developent

New mapper types can be added to the system by implementing mapper modules and placing them in $OMQ_DIR/user/modules/ and adding the modules' names to the qorus.mapper-modules system option.

Each module must call the map_register_mapper() function in the module's init closure or call reference.

Example module:

# -*- mode: qore; indent-tabs-mode: nil -*-
%new-style
%enable-all-warnings
%strict-args
%require-types
module ExampleInboundTableMapper {
version = "1.0";
desc = "example inbound mapper provider module";
author = "Qore Technologies, s.r.o.";
url = "https://qoretechnologies.com";
license = "proprietary";
init = \init();
}
%requires TableMapper
%requires SqlUtil
class ExampleInboundTableMapperType inherits OMQ::InboundTableMapperType {
string getName() {
return "ExampleInboundTableMapper";
}
ExampleInboundTableMapper get(hash mapv, *hash opts) {
return new ExampleInboundTableMapper(mapv, opts);
}
}
sub init() {
# register mappers
map_register_mapper(new ExampleInboundTableMapperType());
}
#! returns the current date
const CurrentDateFilter = date sub (auto v, hash<auto> rec) { return now_us(); };
const DefaultMap = {
"status": {"constant": "I"},
"created_date": {"code": CurrentDateFilter},
};
hash<auto> sub get_wf_map() {
code get_wfiid = softint sub (auto ignored, hash<auto> rec) {
return UserApi::getUserContextInfo().workflow_instanceid;
};
return {
"created_order_id": get_wfiid,
};
}
public namespace ExampleInboundTableMapper;
#! this class provides an easy way to map row data to a single table and adds some default mappings
/** the following default mappings are provided (if the target table has the columns):
- \c "status": constant \c "I"
- \c "created_date": current date/time
- \c "created_order_id": the current workflow_instanceid, if the mapper is created from a workflow
*/
public class ExampleInboundTableMapper::ExampleInboundTableMapper inherits public QorusInboundTableMapper {
private {
#! execution context
hash<auto> cxh = UserApi::getUserContextInfo();
}
public {
}
#! builds the object based on a hash providing field mappings, data constraints, and optionally logic; this variant takes a Datasource/DatasourcePool or other wrapper class as an argument directly
/** throws an exception if a field name in the map is not recognized or if a NOT NULL field is not mapped
@param map the mapper description; see @ref mapperkeys for more info
@param opts see @ref mapperoptions for more info; the following additional keys are required for this class:
- \c "datasource": the name of the Qorus datasource
- \c "table": the name of the target table for inserting
@throw MAP-ERROR the map hash has a logical error (ex: 'trunc' key given without 'maxlen', invalid map key)
@throw UNKNOWN-TABLE table name not recognized (not present in the TableDescriptions hash)
@throw UNKNOWN-COLUMN field name not recognized
@throw MISSING-COLUMN map is missing a mapping for a column with a NOT NULL constraint
*/
constructor(hash mapv, *hash opts) : QorusInboundTableMapper(mapv, ExampleInboundTableMapper::getOpts(opts.table) + opts) {
}
static hash getOpts(string table_name) {
return {
"timezone": "Europe/Prague",
};
}
#! returns a map hash with table properties added from the TableDescriptions hash; throws an exception if the table is not recognized or if a field name in the map is not recognized
/** make sure the table name and all column names are in lower-case
@param mapv the map hash
@return the map hash with table attributes added (numeric fields and varchar2 field widths)
@throw UNKNOWN-TABLE table name not recognized (not present in the TableDescriptions hash)
*/
private setup(hash mapv, *hash opts) {
# get static data if possible
*hash sd = map_try_get_wf_static_data();
# add default mappings as constants
Columns cols = table.describe();
QorusInboundTableMapper::setup(mapv, opts);
hash mymap = DefaultMap;
if (cxh.type == "workflow")
mymap += get_wf_map();
# add default mappings if the mapping doesn't already exist
map mapc.$1 = mymap.$1, keys mymap, (!mapc.$1 && cols.hasKey($1));
}
#! identical to mapData()
hash mapDataHash(hash rec) {
return mapData(rec);
}
}
main Qorus namespace
Definition: QorusRbacAuth.qm:21

Deprecated Connection Definition Files

User connections, Datasource Connections, Qorus to Qorus Connections are defined in connection files with the suffix ".qconn".

Qorus user code should access external resources using user connections in all possible cases because such connections are monitored and the interace is managed (stopped and started) when the dependent connections become unavailable and again available (additionally, operational alerts are issued and cleared in these cases.

When connections are made directly (for example, by using a HTTPClient object directly instead of using a user connection), then the system does not monitor the connection's health, does not manage dependent interface status nor raise or clear alerts when the connection is unavailable or again available.

Deprecated User Connection Definition File Syntax

Note
Use the new YAML connection file syntax as generated by the IDE

Deprecated user connection definition file syntax:

connection-name = ( key = value, ... ) 

The use of whitespace (spaces, newlines, tabs, etc) is allowed; empty lines are ignored. Text after the hash character ('#') indicates the start of a line comment when found outside a quoted string. Quoted strings are allowed, and certain characters must be included in quoted strings and escaped to be used in connection attributes; see Deprecated Connection File Parsing for more information.

Conditional parsing is also supported with the following parse directives:

  • %ifdef: if the given parse define is defined, then the definitions up to the next %else or %endif are parsed, otherwise the block is skipped
  • %ifndef: if the given parse define is not defined, then the definitions up to the next %else or %endif are parsed, otherwise the block is skipped
  • %else: toggles the parsing state from the last %ifdef or %ifndef
  • %endif: closes a conditionally-parsed block

Parse defines are set in the System Options File by system option qorus.defines.

Supported (case sensitive) keys are given in the following table.

User Connection Keys

Key Mandatory? Description Example
url Y full URL for the resource; see connection object types for information on the URLs handled and the object class returned by UserApi::getUserConnection() http://user:pass@localhost:8001
desc N public description of the connection production server 2
tags N key-value pairs to be associated with the connection "tag1=value1, tag2=2, tag3=\"3\""

Additional keys can (and depending on the connection type must) be defined according to supported or required options for the given connection type. See connection object types for information on supported options per connection type.

Note
  • All attributes of user connections are subject to environment variable substitution
  • The "qorus" connection name is provided by default by the QorusConnectionProvider module as a connnection to the local Qorus instance, therefore it's recommended not to use "qorus" for a user or remote connection name
  • User connection configurations are considered to be managed by operations, which means that once a user configuration has been loaded into Qorus, if its configuration is updated with the API, then those API-driven changes are persistent and will not be overwritten by subsequent loads of the user connection by oload.
  • The tag string is parsed with Util::parse_to_qore_value() and must parse to a hash

The following is an example of a connection file using conditional parsing:

%ifdef Production
# production connection definition
sftp-file1 = (
    desc = FILE1 SFTP Polling / Delivery connection,
    url = sftp://file1@sftp.example.com,
    keyfile = /export/home/qorus-prod/.ssh/id_rsa-file1
)
%else
# test/devel connection definition
sftp-file1 = (
    desc = FILE1 SFTP Polling / Delivery connection,
    url = sftp://file1@sftp-test.example.com,
    keyfile = HOME/.ssh/id_rsa-file1
)
%endif
See also
Deprecated Connection File Parsing for more information on the syntax of user connection files

Deprecated Connection File Parsing

Deprecated Connection File Parsing and Special Character Handling

Connection files are parsed as free-form text where whitespace is generally ignored.

The following characters are special in connection files, and can only be used literally when included in quoted strings:

  • ": indicates the start of a quoted string
  • ,: separates option declarations of a connection
  • (: indicates the beginning of option declarations of a connection
  • ): indicates the end of option declarations of a connection
  • $: indicates that environment variable substitution should be performed
Note
  • literal CR ("\r") characters are ignored in connection files; to include a CR character in an attribute, use it in a quoted string as described below
  • quotes (") and parentheses (( and )) can also be used in unquoted strings with leading alphabetic characters for backwards-compatibility with previous versions of Qorus

Quoted strings must be delimited with "; for forward compatibility, it's best to delimit any strings with special characters listed above with ".

Quoted strings accept escape characters; any character may be escaped by prefacing the character with a \ character, however the following escape characters have special values in connection files when escaped:

  • "\n": indicates a newline (ASCII 10)
  • "\r": indicates a carriage return (ASCII 13)
  • "\t": indicates a tab (ASCII 9)

To use one of the special characters listed above, use the character in a quoted string and escape it as in the following example:

https-remote-1 = (
    desc = remote HTTPS connection,
    url = "https://user:'pass'\$\"word\"@example.com:11098",
)

Deprecated Connection File Environment Variable Substitution

All attributes of connection files (remote and user connection files) are subject to environment variable substitution. Any text with the following format will be substituted with the value of the given environment variable:

  • $VAR
  • ${VAR}

For example, in the following file:

fs-staging = (
    desc = Staging filesystem connection,
    url = file://$DIR_ROOT/staging,
)

Assuming that the $DIR_ROOT environment variable is assigned to /project/qorus, then the value of the url option would be set to file:///project/qorus/staging.

To prohibit environment variable substitution and use a literal "$" character in a URL (for example, as a character in a password value in a URL), enclose the string in single or double quotes and place a backslash character before the "$" sign as follows:

https-remote-1 = (
    desc = remote HTTPS connection,
    url = "https://user:pass\$word@example.com:11098",
)

In this way the url option would be set to https://user:pass$word@example.com:11098. Due to environment variable substitution, "$" characters are special characters that must be escaped as in the above examples in quoted strings in connection files to be used literally.