Maintain definition
The maintain engine is used to do operations that don't return data. These operations are valid for updating data in the server. They only return the result of proccess, if operation has been ok or if there has been a problem while doing the operation.
Every element and attribute of maintain targets is listed in the generated XSD reference.
There are several types of maintain operations: insert, update, delete and multiple operations. Also a maintain operation can call a service to do the job (send email, print a report, ...).
You can put as many operations as you want inside a target. I.e. an insert operation followed by two update operations.
Note: All maintains are defined in the Maintain.xml file at global folder. View project structure for more info.
Maintain
This section describes how the operations are made with AWE maintain engine.
XML maintain structure
The simple maintain structure is the next one:
<target name="[target_name]" public="[public]">
<[OPERATION] multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]" schema="[schema_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" sequence="[sequence_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" auto-incremental="[true/false]"/>
... (more fields)
<where>
<and>
<filter left-field="[Field id]" condition="[Condition]" right-variable="[Variable]"/>
... (more filters)
<filter left-field="[Field id]" condition="[Condition]" right-variable="[Variable]"/>
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</[OPERATION]>
</target>
Note: [OPERATION] can be any of the following values:
insert,delete,update,multiple,commit,send-email,queue,serveorretrieve-data.
Maintain element
For easier development of maintain, not all elements are required.
| Element | Use | Multiples instances | Description |
|---|---|---|---|
| target | Required | No | It describe the name of operation |
| insert | Optional | Yes | Is used to do insert operations in database |
| update | Optional | Yes | Is used to do update operations in database |
| delete | Optional | Yes | Is used to do delete operations in database |
| multiple | Optional | Yes | Is used to do multiples operations (insert, delete or update) in database at once |
| commit | Optional | Yes | Is used to do commit in database and store the changes |
| serve | Optional | Yes | Is used to do operations with services (Java or Web services) |
| queue | Optional | Yes | Is used to do operations with queues |
| send-email | Optional | Yes | Send an e-mails |
| retrieve-data | Optional | Yes | Retrieve data from SQL, services, enumerated or queues |
| table | Optional | No | Describes the table over the changes are done |
| where | Optional | No | Defines the conditions that must be met to perform the operation. Is the where sql clause |
| field | Optional | Yes | It describes the columns of table over operate it |
| constant | Optional | Yes | Constant field to update the table |
| operation | Optional | Yes | Operation field to update the table |
| variable | Optional | Yes | Are parameters passed to maintains |
Target element
Target element has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| name | Required | String | Maintain identifier | Note: The name name must be unique |
| public | Optional | Boolean | To set a query as launchable out of session (without being logged) | By default is false |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
| exclusive | Optional | Boolean | To restrict the concurrently execution of target | set this attribute to true if you don't want the target to be executed concurrently (some users at the same time) |
Table element
Table element has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Name of table | Note: Is the real table name in data base |
| schema | Optional | String | Use to set user owner of table | Note: Is the real schema (user) of table in data base |
Where element
The element where has the following structure:
<target name="maintain">
...
<where>
<and>
<filter left-field="[Filter field]" left-table="[Filter table]" condition="[Condition]" right-variable="[Variable]" optional="[Filter Optional]"/>
<filter left-field="[Field 1]" left-table="[Filter table]" condition="[Condition]"
right-field="[Field 2]" right-table="[Table 2]" ignorecase="[Ignorecase]" trim="[Trim]"/>
<filter left-field="[Field]" left-table="[Filter table]" condition="[Condition]" right-query="[Subquery]"/>
<or>
... (more filters or filter groups)
</or>
... (more filters or filter groups)
</and>
<or>
... (more filters or filter groups)
</or>
</where>
...
</target>
Note: There are available two operators for link filters.
<and>and<or>
Filter element
Filter element behaviour is the same as query filter element.
Field element
Field element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Name of field | Note: Is the real column name of table in data base |
| table | Optional | String | Table name of field | |
| alias | Optional | String | Alias of field. It used to describe the field | |
| sequence | Optional | String | Name of sequence to insert from AweKey table | Note: Only apply in insert maintains. It's mandatory to define a new variable without name to use it and assign it to the variable attribute |
| auto-incremental | Optional | Boolean | If field value is retrieve from identity/auto-incremental column type | Note: Only apply in insert maintains. It's mandatory to define a new variable without name to use it and assign it to the variable attribute |
| key | Optional | Boolean | If field is a table key, this value must be set as true | Note: Only apply in multiple maintains |
| audit | Optional | Boolean | Where the field is recorded. true: ONLY on the audit table, the field is NOT written on the table. false: ONLY on the table, the field is NOT audited. Omitted: on both the table and the audit table | Default (omitted) is both |
| optional | Optional | Boolean | Leave this field out of the operation when its variable has no value, instead of writing null | Default value is false. See optional fields |
| variable | Optional | String | Used to set the input field with one variable value | |
| query | Optional | String | Is the query identifier to do a subquery | Note: The query id must exist |
| function | Optional | String | To apply sql function to field | The possible values are defined in field functions |
| cast | Optional | String | Change the field format | The possible values are STRING, INTEGER, LONG, FLOAT and DOUBLE |
Optional fields
By default every declared field reaches the generated statement, so a variable with no value
writes null into its column. With optional="true" the field is left out of the statement
altogether when its variable carries no value:
- on an insert, the column takes its database default instead of
null; - on an update, the column keeps its stored value instead of being overwritten with
null.
<update audit="HISAweThm">
<table id="AweThm"/>
<field id="IdeThm" table="AweThm" variable="themeId"/>
<field id="Nam" table="AweThm" variable="themeName" optional="true"/>
<where>
<and>
<filter left-field="IdeThm" condition="eq" right-variable="themeId"/>
</and>
</where>
<variable id="themeId" type="INTEGER" name="themeId"/>
<variable id="themeName" type="STRING" name="themeName"/>
</update>
Sending themeId without themeName updates only IdeThm; the stored Nam is untouched.
Note: "No value" means null or empty, the same rule that
optionalalready follows on query filters, so the attribute behaves consistently in both places.
Note: The attribute applies to
insertandupdate. Adeletebuilds no field list, so it is unaffected.
Note: Audit tables are not affected: they record the operation that was requested and their columns are nullable, so the history still keeps a row for the omitted column.
⚠️ Limitation: A field bound to a list variable (a batch maintain) is never omitted. Every row of a batch shares a single column list, so leaving a column out for one row only is not representable in the statement.
Constant element
The constant element has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Name of field | Note: Is the real column name of table in data base |
| table | Optional | String | Table name of field | |
| function | Optional | String | To apply sql function to field | The possible values are defined in field functions |
| cast | Optional | String | Change the field format | The possible values are STRING, INTEGER, LONG, FLOAT and DOUBLE |
| value | Required | String | A static value to be used as field value | |
| type | Optional | String | Type of the value | The possible values are available here |
Operation element
The operation element allows to define operation between fields and will be resolved as SQL clauses:
<operation operator="[operator]" alias="[alias]">
<constant value="[constant value]" />
<field id="[field name]" table="[field table]" />
...
</operation>
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Name of field | Note: Is the real column name of table in data base |
| table | Optional | String | Table name of field | |
| operator | Required | String | Operator of the operation | See operator attribute |
| function | Optional | String | To apply sql function to field | The possible values are defined in field functions |
| cast | Optional | String | Change the field format | The possible values are STRING, INTEGER, LONG, FLOAT and DOUBLE |
Variable element
Variable element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Is the identifier name of variable | Note: The id must be unique |
| type | Required | String | Describe the type of variable | Can be STRING, INTEGER, etc. |
| name | Optional | String | Name of a variable | The variable is the name of a criterion defined in the screen |
| optional | Optional | Boolean | Setting this attribute to true will avoid an error in case of variable value can't be retrieved | Default value is false |
| value | Optional | String | Value | |
| property | Optional | String | Name of property | |
| session | Optional | String | Name of session variable |
Sql maintain
Insert
Insert element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| multiple | Optional | String | If true this operation will be launched as many times as defined list variable values are, if audit this operation will be audited as many times as defined list variable values are | true or audit. When omitted the operation runs once |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
| audit | Optional | String | The name of the audit table where audit values are going to be stored | Note: Audit table must exist |
| query | Optional | String | Name of a query to retrieve data from an INSERT INTO SELECT statement | Note: If audit is also defined, AWE reuses the same source rowset for the base insert and the audit rows |
| batch | Optional | Boolean | Do the operation in batch chunks | Default value is false |
| batch-size | Optional | Integer | Batch chunk size | Default value is the defined in properties |
Note: You can view
fieldelement information here
The insert maintain structure is the next one:
<target name="[target_name]" public="[public]">
<insert multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" sequence="[sequence_name]"/>
... (more fields)
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</insert>
</target>
Important: the name of
sequenceattribute has been exist in AweKey table
INSERT examples
<!-- Insert into AweQue table -->
<target name="QueNew">
<insert audit="HISAweQue">
<table id="AweQue"/>
<field id="IdeAweQue" sequence="JmsKey" variable="IdeAweQue"/>
<field id="Als" variable="Als"/>
<field id="Des" variable="Des"/>
<field id="QueTyp" variable="QueTyp"/>
<field id="Act" variable="Act"/>
<variable id="IdeAweQue" type="INTEGER" name="IdeAweQue" />
<variable id="Als" type="STRING" name="Als" />
<variable id="Des" type="STRING" name="Des" />
<variable id="QueTyp" type="STRING" name="QueTyp" />
<variable id="Act" type="INTEGER" name="Act" value="1"/>
</insert>
<commit/>
<serve service="RelJmsCon"/>
</target>
<!-- Insert with historic data -->
<target name="SitNew">
<insert audit="HISAweSit">
<table id="AweSit"/>
<field id="IdeSit" sequence="SitKey" variable="IdeSit"/>
<field id="Nam" variable="Nam"/>
<field id="Ord" variable="Ord"/>
<field id="Act" variable="Act"/>
<variable id="Nam" type="STRING" name="Nam" />
<variable id="Ord" type="INTEGER" name="Ord" />
<variable id="Act" type="INTEGER" name="Act" />
<variable id="IdeSit" type="INTEGER" name="IdeSit" />
</insert>
</target>
Inserts with auto‑increment columns (IDENTITY/AUTO INCREMENT)
When the database generates the primary key automatically (IDENTITY/AUTO INCREMENT), for insert operations you must:
- Mark the auto‑increment column with
auto-incremental="true"in thefieldelement so that AWE retrieves the generated id after the insert. - Declare a
variablefor that field to store the generated value. You don't need to pass it as input; AWE will fill it with the generated id and you can reuse it within the sametarget(e.g., for subsequent operations) or return it to the client. - Do not set
sequenceon auto‑increment columns (sequences only apply to AWE sequences stored in theAweKeytable).
Example using the TestAutoIncrement table (with id as IDENTITY):
<!-- Insert into a table with an auto‑increment (IDENTITY) primary key -->
<target name="TstAutoIncNew">
<insert>
<table id="TestAutoIncrement"/>
<!-- Mark the identity column as key and declare the variable to capture the generated id -->
<field id="id" auto-incremental="true" variable="id"/>
<field id="name" variable="name"/>
<field id="email" variable="email"/>
<!-- Input variables -->
<variable id="name" type="STRING" name="name"/>
<variable id="email" type="STRING" name="email"/>
<!-- Output variable that will hold the generated id after the insert -->
<variable id="id" type="INTEGER"/>
</insert>
</target>
Note: In
multiplemaintains, it is also mandatory to have afieldwithauto-incremental="true"to indicate the table key. The same convention applies when the key is generated by the database.
Example reusing the generated id in a follow‑up insert (parent tst_order and its tst_order_item rows):
<target name="insertWithKeySingle">
<!-- First insert: capture the generated OrderId from tst_order.id -->
<insert>
<table id="tst_order"/>
<!-- Mark the identity column as auto-incremental="true" and declare the variable to capture the generated id -->
<field id="id" auto-incremental="true" variable="OrderId"/>
<field id="order_date" variable="OrderDate"/>
<constant id="order_comments" value="Test Order"/>
<variable id="OrderDate" type="SYSTEM_DATE" name="OrderDate"/>
<!-- Output variable filled by AWE with the generated id -->
<variable id="OrderId" type="INTEGER" name="OrderId"/>
</insert>
<!-- Second insert (multiple): reuse OrderId to insert order items -->
<insert multiple="true">
<table id="tst_order_item"/>
<field id="order_id" variable="OrderId"/>
<field id="order_product" variable="ProductName"/>
<field id="order_price" variable="ProductPrice"/>
<field id="order_quantity" variable="ProductQuantity"/>
<variable id="OrderId" type="INTEGER" name="OrderId"/>
<variable id="ProductName" type="STRING" name="order_product"/>
<variable id="ProductPrice" type="FLOAT" name="order_price"/>
<variable id="ProductQuantity" type="INTEGER" name="order_quantity"/>
</insert>
</target>
Insert into select
The INSERT INTO SELECT statement is another way to make an insert statement, but retrieving data from a subquery. The structure of an INSERT INTO SELECT statement is the following:
<target name="[target_name]" public="[public]">
<insert query="[query_to_retrieve_data_from]">
<table id="[table_name]"/>
<field id="[field_name]"/>
... (more fields)
</insert>
</target>
Note: The number of fields defined on
INSERT INTO SELECTstatement and subquery must match.
Note: When
auditis defined together withquery, the audit rows are generated from the same source rows used by the base insert. Empty source queries insert zero base rows and zero audit rows.
INSERT INTO SELECT examples
<!-- Insert into select (maintain.xml) -->
<target name="test">
<insert query="testData">
<table id="test"/>
<field id="Nam"/>
<field id="Ord"/>
</insert>
</target>
<!-- Query for data retrieving (queries.xml) -->
<query id="testData" distinct="true">
<table id="AweKey" />
<field id="KeyNam"/>
<field id="Act"/>
</query>
This will generate the next SQL code:
INSERT INTO test (Nam, Ord) SELECT DISTINCT KeyNam, Act FROM AweKey
Update
Update element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| multiple | Optional | String | If true this operation will be launched as many times as defined list variable values are, if audit this operation will be audited as many times as defined list variable values are | true or audit. When omitted the operation runs once |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
| audit | Optional | String | The name of the audit table where audit values are going to be stored | Note: Audit table must exist |
| batch | Optional | Boolean | Do the operation in batch chunks | Default value is false |
| batch-size | Optional | Integer | Batch chunk size | Default value is the defined in properties |
Note: You can view
whereelement information here
The update maintain structure is the next one:
<target name="[target_name]" public="[public]">
<update multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" audit="[audit]"/>
... (more fields)
<where>
<and>
<filter left-field="[filter_field]" left-table="[filter_field_table]" condition="[filter_condition]"
right-variable="[filter_variable]" ignorecase="[filter_ignore_case]" trim="[filter_trim]"/>
... (more filters)
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</update>
</target>
Update examples
<!-- Manage User as logged out -->
<target name="MgrUsrLogOut" public="true">
<!-- Mark User as logged out -->
<update>
<table id="ope"/>
<field id="l1_con" variable="Con"/>
<field id="l1_dat" variable="SysDat"/>
<where>
<and>
<filter left-field="l1_nom" condition="eq" right-variable="Usr" ignorecase="true"/>
</and>
</where>
<variable id="Con" type="INTEGER" value="0"/>
<variable id="SysDat" type="SYSTEM_DATE" />
<variable id="Usr" type="STRING" session="user" optional="false"/>
</update>
</target>
<target name="UsrUpd">
<update>
<table id="ope"/>
<field id="l1_act" variable="Sta"/>
<field id="WebPrn" variable="WebPrn"/>
<field id="PcPrn" variable="PcPrn"/>
<field id="EmlAdr" variable="Eml"/>
<field id="EmlSrv" variable="EmlSrv"/>
<field id="l1_lan" variable="Lan"/>
<field id="OpeNam" variable="Nam"/>
<field id="IdePro" variable="Pro"/>
<field id="IdeThm" variable="Thm"/>
<field id="ScrIni" variable="ScrIni"/>
<field id="Res" variable="Res"/>
<field id="PwdLck" variable="PwdLck"/>
<where>
<and>
<filter left-field="IdeOpe" condition="eq" right-variable="IdeOpe"/>
</and>
</where>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe" />
<variable id="Sta" type="INTEGER" name="Sta" />
<variable id="WebPrn" type="STRINGN" name="WebPrn" />
<variable id="PcPrn" type="STRINGN" name="PcPrn" />
<variable id="Eml" type="STRINGN" name="Eml" />
<variable id="EmlSrv" type="STRINGN" name="EmlSrv" />
<variable id="Lan" type="STRINGN" name="Lan" />
<variable id="Nam" type="STRINGN" name="Nam" />
<variable id="Pro" type="INTEGER" name="Pro" />
<variable id="Thm" type="INTEGER" name="Thm" />
<variable id="ScrIni" type="STRING" name="ScrIni" />
<variable id="Res" type="STRING" name="Res" />
<variable id="PwdLck" type="INTEGER" name="PwdLck" />
</update>
</target>
Delete
Delete element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| multiple | Optional | String | If true this operation will be launched as many times as defined list variable values are, if audit this operation will be audited as many times as defined list variable values are | true or audit. When omitted the operation runs once |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
| audit | Optional | String | The name of the audit table where audit values are going to be stored | Note: Audit table must exist |
| batch | Optional | Boolean | Do the operation in batch chunks | Default value is false |
| batch-size | Optional | Integer | Batch chunk size | Default value is the defined in properties |
Note: You can view
whereelement information here
The delete maintain structure is the next one:
<target name="[target_name]" public="[public]">
<delete multiple="[multiple]" audit="[audit_table]">
<table id="[table_name]"/>
<field id="[field_name]" table="[table_name]" variable="[field_variable_name]" audit="[audit]"/>
<where>
<and>
<filter left-field="[filter_field]" left-table="[filter_field_table]" condition="[filter_condition]"
right-variable="[filter_variable]" ignorecase="[filter_ignore_case]" trim="[filter_trim]"/>
... (more filters)
</and>
</where>
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" list="[variable_list]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]" />
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</delete>
</target>
Delete examples
<!-- Delete maintain with historic operation -->
<target name="ProDel">
<delete audit="HISAweModPro">
<table id="AweModPro"/>
<field id="IdePro" variable="IdePro" audit="true"/>
<where>
<and>
<filter left-field="IdePro" condition="eq" right-variable="IdePro" />
</and>
</where>
<variable id="IdePro" type="INTEGER" name="IdePro"/>
</delete>
</target>
<!-- Delete maintain with multiple atributte -->
<target name="UsrDel">
<delete multiple="true">
<table id="ope"/>
<where>
<and>
<filter left-field="IdeOpe" condition="eq" right-variable="IdeOpe"/>
</and>
</where>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe"/>
</delete>
</target>
Multiple
The multiple maintains are used in Grid widget to perform sql operations.
Multiple element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| grid | Required | String | Is the grid name where operations are performed | |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
| audit | Optional | String | The name of the audit table where audit values are going to be stored | Note: Audit table must exist |
IMPORTANT: It must exist one field with attribute
key="true"to indicate which field is the table key
Multiple examples
<!-- Screen Access Multiple -->
<target name="ScrAccUpd">
<multiple audit="HISAweScrRes" grid="GrdScrAccLst">
<table id="AweScrRes"/>
<field id="IdeAweScrRes" variable="IdeAweScrRes" sequence="ScrResKey" key="true"/>
<field id="IdePro" variable="IdePro"/>
<field id="IdeOpe" variable="IdeOpe"/>
<field id="IdeMod" variable="IdeMod"/>
<field id="Opt" variable="Opt"/>
<field id="AccMod" variable="AccMod"/>
<field id="Act" variable="Act"/>
<variable id="IdeAweScrRes" type="INTEGER" name="IdeAweScrRes"/>
<variable id="IdeOpe" type="INTEGER" name="IdeOpe" optional="true"/>
<variable id="IdePro" type="INTEGER" name="IdePro" optional="true"/>
<variable id="IdeMod" type="INTEGER" name="IdeMod" optional="true"/>
<variable id="Opt" type="STRING" name="Opt" />
<variable id="AccMod" type="STRING" name="AccMod"/>
<variable id="Act" type="INTEGER" name="Act" />
</multiple>
</target>
<!-- AweKey Update Multiple -->
<target name="AweKeyUpd">
<multiple grid="GrdKeyLst">
<table id="AweKey"/>
<field id="KeyNam" variable="KeyNam" key="true"/>
<field id="KeyVal" variable="KeyVal"/>
<field id="Act" variable="Act"/>
<variable id="KeyNam" type="STRING" name="KeyNam"/>
<variable id="KeyVal" type="INTEGER" name="KeyVal"/>
<variable id="Act" type="INTEGER" name="Act"/>
</multiple>
</target>
Audits
Audits are managed automatically with AWE, but the audit tables must be created on development time and they need to have at least three key fields:
- Audit user - User who is doing the operation
- Audit timestamp - Date and time of the audit operation
- Audit type - Insert
(I), Update(U)or Delete(D)operation
Commit
The tag <commit/> is used into maintain targets to force the data stored in the database. Usually, used between different maintenance operations to ensure that the data are correct before proceeding to the next step. See Transactions for how it works with the maintain transaction.
Commit example
<!-- Do commit before execute service operation -->
<target name="DbsDel">
<delete multiple="true" audit="HISAweSitModDbs">
<table id="AweSitModDbs"/>
<field id="IdeDbs" variable="IdeDbs" audit="true"/>
<where>
<and>
<filter left-field="IdeDbs" condition="eq" right-variable="IdeDbs" />
</and>
</where>
<variable id="IdeDbs" type="INTEGER" name="IdeDbs"/>
</delete>
<delete multiple="true" audit="HISAweDbs">
<table id="AweDbs"/>
<field id="IdeDbs" variable="IdeDbs" audit="true" />
<field id="Als" variable="Als" audit="true" />
<field id="Des" variable="Des" audit="true" />
<field id="Dct" variable="Dct" audit="true" />
<field id="Typ" variable="Typ" audit="true" />
<field id="Dbt" variable="Dbt" audit="true" />
<field id="Dbc" variable="Dbc" audit="true" />
<where>
<and>
<filter left-field="IdeDbs" condition="eq" right-variable="IdeDbs" />
</and>
</where>
<variable id="IdeDbs" type="INTEGER" name="IdeDbs" />
<variable id="Als" type="STRING" name="Als" />
<variable id="Des" type="STRINGN" name="Des" />
<variable id="Dct" type="STRING" name="Dct" />
<variable id="Dbt" type="STRING" name="Dbt" />
<variable id="Typ" type="STRING" name="Typ" />
<variable id="Dbc" type="STRING" name="Dbc" />
</delete>
<commit/>
<serve service="RelDbsCon"/>
</target>
Transactions
Each maintain runs inside one database transaction of its datasource. When the maintain ends without error the
transaction is committed; when a statement fails, or a step returns an ERROR result, the whole maintain is rolled
back. This is controlled by awe.maintain.transaction.enabled (true by default, new in AWE 5).
# Default. Set to false to get the AWE 4 behavior described below
awe.maintain.transaction.enabled=true
What the transaction covers
The transaction belongs to the datasource of the maintain: the default datasource, or the one selected with the
database parameter when awe.database.multidatabase-enable=true. Everything that runs on that datasource while the
maintain runs joins it (Spring PROPAGATION_REQUIRED):
| Step of the maintain | With the transaction (default) |
|---|---|
insert, update, delete, multiple, audits (HIS* tables), include-target | Same transaction. A failure rolls back every previous statement of the maintain. |
retrieve-data | Joins the transaction, so it sees the rows written before it by the same maintain. |
serve with a Java service that launches another maintain on the same datasource | The nested maintain joins the outer one: it is committed or rolled back with it. |
A step that returns a ServiceData of type ERROR without throwing | The maintain is rolled back and the error response is returned as it is. |
<commit/> | Commits the transaction in the middle of the maintain, as before: the work before it stays even if a later step fails. |
A maintain launched inside a Spring @Transactional method (or a TransactionTemplate) of the application on the same datasource | Joins the application transaction: it is committed or rolled back with it. |
| A maintain on a different datasource | Runs in its own transaction of that datasource. |
queue (JMS) and email steps | Not transactional: a message or an email that was sent is not undone by a rollback. |
REST and microservice calls (serve with a REST or microservice service) | Not transactional: the remote side is not rolled back. |
Points to keep in mind:
- A swallowed failure still rolls back. If a Java service catches the exception of a nested maintain, or ignores
its
ERRORresult, and returnsOK, the outer maintain fails at commit time with the generic maintain error and everything is rolled back. Let the error propagate instead of hiding it. - Inside an application transaction, a failing maintain only marks it for rollback. Its rows are undone when the
application transaction ends, not before: until then the same transaction still sees them, and committing it fails
with Spring's
UnexpectedRollbackException. <commit/>in a nested maintain commits the outer work too, because both share the same connection.- Java code that calls the
launchMaintainorlaunchPrivateMaintainoverloads that take a maintain id and aDatabaseConnectionowns that connection: AWE does not open a transaction for it and keeps the AWE 4 behavior (commit and release at the end, or nothing withkeepAliveConnection=true). ThelaunchMaintain(Target, ...)overload opens the transaction when theDatabaseConnectionhas not acquired its connection yet. - Joining needs the same
DataSourceobject. Withawe.database.multidatabase-enable=true, a maintain without the database parameter uses the routing datasource, and one with an explicit alias uses the pool of that alias. They do not join each other even when both point to the same physical database. - JMS listeners. AWE's JMS listener container uses the Spring Boot transaction manager, so a maintain launched from a queue listener joins the listener transaction (in AWE 4 it committed on its own).
- Broadcasts before the commit. A notification broadcast (notifier) sent from a step of a long maintain can reach the client before the maintain commits, so the client may not see the row yet.
Disabling it (AWE 4 behavior)
With awe.maintain.transaction.enabled=false the maintains behave as in AWE 4:
- Each maintain disables the auto-commit of its own connection, commits at the end and rolls back its own statements on an exception.
retrieve-dataand nested maintains launched from Java services use other connections: a nested maintain commits on its own, so it stays committed when the outer maintain fails afterwards, andretrieve-datadoes not see the uncommitted rows of the maintain.- A step that returns an
ERRORresult without an exception does not roll back: the maintain is committed. - A maintain launched inside an application transaction commits on its own connection.
Disable it only if an application depends on these partial commits, for example a Java service that must keep the rows of a nested maintain even when the outer maintain fails. In that case, prefer moving that nested work to its own maintain launched after the outer one.
Connection lifecycle by connector
Audit of how each connector gets and releases its connection (issue #781):
| Connector | Connection | Commit and rollback |
|---|---|---|
SQLMaintainConnector / SQLMaintainBuilder (insert, update, delete, multiple, audits, batches) | The connection of the maintain, passed by MaintainService. | None of its own: MaintainService (or the transaction) owns them. Errors propagate as AWEQueryException. |
SQLQueryConnector (retrieve-data, queries) | DataSourceUtils.getConnection on the datasource, released after the query. | None. Joins the maintain transaction when there is one; otherwise it is a separate connection. |
ServiceMaintainConnector → JavaConnector, RestConnector, MicroserviceConnector | No connection is passed to the service. Maintains launched by a Java service get the connection of the active transaction of their datasource, or a new one. | Java services: as the maintains they launch. REST and microservice: remote, not transactional. A Java service that returns ERROR without an exception rolls back only with the transaction enabled. |
QueueMaintainConnector / QueueBuilder | No JDBC connection (JmsTemplate). | Messages are sent at once; a rollback does not undo them. |
EmailMaintainConnector / EmailService | Its queries use QueryService (see SQLQueryConnector). | Emails are sent at once; a rollback does not undo them. |
MaintainService.getNextSequenceValue | The connection it receives (or a new one), always released at the end. | None. |
Other findings of the audit: DatabaseConnection.getConnection() returns null when the datasource cannot give a
connection (with the transaction enabled the maintain fails when the transaction begins instead); the auto-commit
flag is not restored before releasing the connection in the AWE 4 path (Hikari restores it when the connection
returns to the pool); and a rollback that fails hides the original error in both paths.
Service maintain
Are used to call services (Java or Web services) from maintain operation.
Service maintain has the following xml structure:
<target name="[target_name]" exclusive="[exclusive]" public="[public]">
<serve service="[service_name]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]"/>
<variable id="[variable_name]" type="[variable_type]" value="[static_value]"/>
<variable id="[variable_name]" type="[variable_type]" session="[session_variable]"/>
... (more variables)
</serve>
</target>
IMPORTANT: Service maintain must have
<serve>element. The service name must exist in fileServices.xml. You can see services for more information.
Serve element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| service | Required | String | Service identifier | Note: The service id must exist in Services.xml file |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
Service maintain examples
<!-- Serve example -->
<target name="[target_name]">
<serve service="RelAllScrCfg" />
<serve service="LoaScrCfgByDbs">
<variable id="database" type="STRING" session="database"/>
</serve>
</target>
<!-- Clear profile Cache -->
<target name="ClrCchPrf">
<serve service="ClrCch">
<variable id="cache" type="STRING" value="PROFILE"/>
</serve>
</target>
Queue maintain
Are used to send message to Jms queue from maintain operation.
Queue maintain has the following xml structure:
<target name="[target_name]" >
<queue name="[Id_queue]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</queue>
</target>
IMPORTANT: Queue maintain must have
<queue>element. The queue name must exist in fileQueues.xml. You can see queues for more information.
Queue element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| name | Required | String | Queue identifier | Note: The queue id must exist in Queues.xml file |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
Queue maintain examples
<!-- Test queues -->
<target name="TstQueSndSyn">
<queue name="TstQueSndSyn">
<variable id="Usr" type="STRING" name="CrtNam"/>
</queue>
</target>
Email maintain
Are used to send e-mails from maintain operation.
Email maintain has the following xml structure:
<target name="[target_name]" >
<send-email name="[Email Id]">
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</send-email>
</target>
IMPORTANT: Email maintain must have
<send-email>element. The Email identifier must exist in fileEmail.xml. You can see email definition for more information.
Email element in maintains has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| id | Required | String | Email identifier | Note: The email id must exist in Email.xml file |
| label | Optional | String | Is used to set the output message after executing maintenance | Note: You can use i18n files (locales) |
Email maintain examples
<!-- Send reports by e-mail -->
<target name="SndRep">
<send-email id="SndRep"/>
</target>
Include target
You can add an include-target tag to allow reuse defined targets instead of rewriting them.
Include target has the following xml structure:
<target name="[Target name]" >
<include-target name="[target-to-include]"/>
</target>
IMPORTANT: Include target must have
<include-target>element. The[target-to-include]must exist in any ofMaintain.xmlfiles.
Include target has the following attributes:
| Attribute | Use | Type | Description | Values |
|---|---|---|---|---|
| name | Required | String | Target identifier | Note: The target name must exist in Maintain.xml file |
Include target examples
<!-- Test insert -->
<target name="testInsert">
<insert>
<table id="HISAweMod" />
<field id="HISope" variable="User" />
<field id="HISdat" variable="Date" />
<field id="HISact" variable="Action" />
<field id="Nam" variable="Nam" />
<field id="IdeThm" variable="Thm" />
<field id="ScrIni" variable="Scr" />
<field id="Act" variable="Act" />
<variable id="Nam" type="STRING" value="testIncludeTarget" />
<variable id="Thm" type="INTEGER" value="1" />
<variable id="Scr" type="STRING" value="testIncludeTarget" />
<variable id="Act" type="INTEGER" value="1" />
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Date" type="SYSTEM_DATE"/>
<variable id="Action" type="STRING" value="T" />
</insert>
</target>
<!-- Test update -->
<target name="testUpdate">
<update>
<table id="HISAweMod" />
<field id="Nam" variable="Nam" />
<field id="IdeThm" variable="Thm" />
<field id="ScrIni" variable="Scr" />
<field id="Act" variable="Act" />
<where>
<and>
<filter left-field="HISope" condition="eq" right-variable="User"/>
<filter left-field="HISact" condition="eq" right-variable="Action"/>
</and>
</where>
<variable id="Nam" type="STRING" value="testIncludeTargetUpd" />
<variable id="Thm" type="INTEGER" value="2" />
<variable id="Scr" type="STRING" value="testIncludeTargetUpd" />
<variable id="Act" type="INTEGER" value="2" />
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Action" type="STRING" value="T" />
</update>
</target>
<!-- Test delete -->
<target name="testDelete">
<delete>
<table id="HISAweMod" />
<where>
<and>
<filter left-field="HISope" condition="eq" right-variable="User"/>
<filter left-field="HISact" condition="eq" right-variable="Action"/>
</and>
</where>
<variable id="User" type="STRING" value="testIncludeTarget" />
<variable id="Action" type="STRING" value="T" />
</delete>
</target>
<!-- Test include -->
<target name="testInclude">
<include-target name="testInsert"/>
<include-target name="testUpdate"/>
<include-target name="testDelete"/>
</target>
Retrieve data
Retrieve data target is useful to retrieve some data from a query (SQL, service, enumerated, etc.) and send it to a maintain process.
Retrieve data has the following xml structure:
<target name="[target_name]">
<retrieve-data service="[service_id]" enumerated="[enumerated_id]" queue="[queue_id]">
<table .../>
<field alias="[field_alias]"
<variable id="[variable_name]" type="[variable_type]" name="[parameter_name]" [[list="list"]
[session="session_variable"] [value="static_value"] [property="property_value"]]/>
... (more variables)
</retrieve-data>
</target>
retrieve-data tag works as a query defined on queries.xml. Every retrieved column will be
stored as a parameter named as the column field alias.
NOTE: If you are using AWE sequences, you should consider to prioritize this way of retrieving data for inserting it rather to
INSERT INTO SELECTstatements.
Retrieve data examples
<target name="testRetrieveDataAndInsertAfter">
<retrieve-data>
<table id="Table1"/>
<field id="Field1" alias="name"/>
<field id="Field2" alias="screen"/>
<field id="Field3" alias="user"/>
<field id="Field4" alias="action"/>
</retrieve-data>
<insert multiple="true">
<table id="Table2"/>
<field id="User" variable="User"/>
<field id="Date" variable="Date"/>
<field id="Action" variable="Action"/>
<field id="Name" variable="Nam"/>
<field id="Active" variable="Active"/>
<variable id="User" type="STRING" name="user"/>
<variable id="Date" type="SYSTEM_DATE"/>
<variable id="Action" type="STRING" name="action"/>
<variable id="Name" type="STRING" name="name"/>
<variable id="Active" type="INTEGER" value="1"/>
</insert>
</target>
This sample will retrieve a list of variables named name, screen, user and action
and will use them as input parameters for insert statement to Table2.