Skip to main content
Version: Next (5.0)

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.

tip

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.

Maintain engine
info

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, serve or retrieve-data.

Maintain element​

For easier development of maintain, not all elements are required.

ElementUseMultiples instancesDescription
targetRequiredNoIt describe the name of operation
insertOptionalYesIs used to do insert operations in database
updateOptionalYesIs used to do update operations in database
deleteOptionalYesIs used to do delete operations in database
multipleOptionalYesIs used to do multiples operations (insert, delete or update) in database at once
commitOptionalYesIs used to do commit in database and store the changes
serveOptionalYesIs used to do operations with services (Java or Web services)
queueOptionalYesIs used to do operations with queues
send-emailOptionalYesSend an e-mails
retrieve-dataOptionalYesRetrieve data from SQL, services, enumerated or queues
tableOptionalNoDescribes the table over the changes are done
whereOptionalNoDefines the conditions that must be met to perform the operation. Is the where sql clause
fieldOptionalYesIt describes the columns of table over operate it
constantOptionalYesConstant field to update the table
operationOptionalYesOperation field to update the table
variableOptionalYesAre parameters passed to maintains

Target element​

Target element has the following attributes:

AttributeUseTypeDescriptionValues
nameRequiredStringMaintain identifierNote: The name name must be unique
publicOptionalBooleanTo set a query as launchable out of session (without being logged)By default is false
labelOptionalStringIs used to set the output message after executing maintenanceNote: You can use i18n files (locales)
exclusiveOptionalBooleanTo restrict the concurrently execution of targetset 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:

AttributeUseTypeDescriptionValues
idRequiredStringName of tableNote: Is the real table name in data base
schemaOptionalStringUse to set user owner of tableNote: 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:

AttributeUseTypeDescriptionValues
idRequiredStringName of fieldNote: Is the real column name of table in data base
tableOptionalStringTable name of field
aliasOptionalStringAlias of field. It used to describe the field
sequenceOptionalStringName of sequence to insert from AweKey tableNote: 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-incrementalOptionalBooleanIf field value is retrieve from identity/auto-incremental column typeNote: 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
keyOptionalBooleanIf field is a table key, this value must be set as trueNote: Only apply in multiple maintains
auditOptionalBooleanWhere 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 tableDefault (omitted) is both
optionalOptionalBooleanLeave this field out of the operation when its variable has no value, instead of writing nullDefault value is false. See optional fields
variableOptionalStringUsed to set the input field with one variable value
queryOptionalStringIs the query identifier to do a subqueryNote: The query id must exist
functionOptionalStringTo apply sql function to fieldThe possible values are defined in field functions
castOptionalStringChange the field formatThe 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 optional already follows on query filters, so the attribute behaves consistently in both places.

Note: The attribute applies to insert and update. A delete builds 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:

AttributeUseTypeDescriptionValues
idRequiredStringName of fieldNote: Is the real column name of table in data base
tableOptionalStringTable name of field
functionOptionalStringTo apply sql function to fieldThe possible values are defined in field functions
castOptionalStringChange the field formatThe possible values are STRING, INTEGER, LONG, FLOAT and DOUBLE
valueRequiredStringA static value to be used as field value
typeOptionalStringType of the valueThe 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>
AttributeUseTypeDescriptionValues
idRequiredStringName of fieldNote: Is the real column name of table in data base
tableOptionalStringTable name of field
operatorRequiredStringOperator of the operationSee operator attribute
functionOptionalStringTo apply sql function to fieldThe possible values are defined in field functions
castOptionalStringChange the field formatThe possible values are STRING, INTEGER, LONG, FLOAT and DOUBLE

Variable element​

Variable element in maintains has the following attributes:

AttributeUseTypeDescriptionValues
idRequiredStringIs the identifier name of variableNote: The id must be unique
typeRequiredStringDescribe the type of variableCan be STRING, INTEGER, etc.
nameOptionalStringName of a variableThe variable is the name of a criterion defined in the screen
optionalOptionalBooleanSetting this attribute to true will avoid an error in case of variable value can't be retrievedDefault value is false
valueOptionalStringValue
propertyOptionalStringName of property
sessionOptionalStringName of session variable

Sql maintain​

Insert​

Insert element in maintains has the following attributes:

AttributeUseTypeDescriptionValues
multipleOptionalStringIf 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 aretrue or audit. When omitted the operation runs once
labelOptionalStringIs used to set the output message after executing maintenanceNote: You can use i18n files (locales)
auditOptionalStringThe name of the audit table where audit values are going to be storedNote: Audit table must exist
queryOptionalStringName of a query to retrieve data from an INSERT INTO SELECT statementNote: If audit is also defined, AWE reuses the same source rowset for the base insert and the audit rows
batchOptionalBooleanDo the operation in batch chunksDefault value is false
batch-sizeOptionalIntegerBatch chunk sizeDefault value is the defined in properties

Note: You can view field element 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 sequence attribute 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 the field element so that AWE retrieves the generated id after the insert.
  • Declare a variable for 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 same target (e.g., for subsequent operations) or return it to the client.
  • Do not set sequence on auto‑increment columns (sequences only apply to AWE sequences stored in the AweKey table).

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 multiple maintains, it is also mandatory to have a field with auto-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 SELECT statement and subquery must match.

Note: When audit is defined together with query, 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:

AttributeUseTypeDescriptionValues
multipleOptionalStringIf 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 aretrue or audit. When omitted the operation runs once
labelOptionalStringIs used to set the output message after executing maintenanceNote: You can use i18n files (locales)
auditOptionalStringThe name of the audit table where audit values are going to be storedNote: Audit table must exist
batchOptionalBooleanDo the operation in batch chunksDefault value is false
batch-sizeOptionalIntegerBatch chunk sizeDefault value is the defined in properties

Note: You can view where element 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:

AttributeUseTypeDescriptionValues
multipleOptionalStringIf 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 aretrue or audit. When omitted the operation runs once
labelOptionalStringIs used to set the output message after executing maintenanceNote: You can use i18n files (locales)
auditOptionalStringThe name of the audit table where audit values are going to be storedNote: Audit table must exist
batchOptionalBooleanDo the operation in batch chunksDefault value is false
batch-sizeOptionalIntegerBatch chunk sizeDefault value is the defined in properties

Note: You can view where element 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:

AttributeUseTypeDescriptionValues
gridRequiredStringIs the grid name where operations are performed
labelOptionalStringIs used to set the output message after executing maintenanceNote: You can use i18n files (locales)
auditOptionalStringThe name of the audit table where audit values are going to be storedNote: 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 maintainWith the transaction (default)
insert, update, delete, multiple, audits (HIS* tables), include-targetSame transaction. A failure rolls back every previous statement of the maintain.
retrieve-dataJoins 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 datasourceThe nested maintain joins the outer one: it is committed or rolled back with it.
A step that returns a ServiceData of type ERROR without throwingThe 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 datasourceJoins the application transaction: it is committed or rolled back with it.
A maintain on a different datasourceRuns in its own transaction of that datasource.
queue (JMS) and email stepsNot 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 ERROR result, and returns OK, 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 launchMaintain or launchPrivateMaintain overloads that take a maintain id and a DatabaseConnection owns that connection: AWE does not open a transaction for it and keeps the AWE 4 behavior (commit and release at the end, or nothing with keepAliveConnection=true). The launchMaintain(Target, ...) overload opens the transaction when the DatabaseConnection has not acquired its connection yet.
  • Joining needs the same DataSource object. With awe.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-data and 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, and retrieve-data does not see the uncommitted rows of the maintain.
  • A step that returns an ERROR result 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):

ConnectorConnectionCommit 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, MicroserviceConnectorNo 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 / QueueBuilderNo JDBC connection (JmsTemplate).Messages are sent at once; a rollback does not undo them.
EmailMaintainConnector / EmailServiceIts queries use QueryService (see SQLQueryConnector).Emails are sent at once; a rollback does not undo them.
MaintainService.getNextSequenceValueThe 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 file Services.xml. You can see services for more information.

Serve element in maintains has the following attributes:

AttributeUseTypeDescriptionValues
serviceRequiredStringService identifierNote: The service id must exist in Services.xml file
labelOptionalStringIs used to set the output message after executing maintenanceNote: 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 file Queues.xml. You can see queues for more information.

Queue element in maintains has the following attributes:

AttributeUseTypeDescriptionValues
nameRequiredStringQueue identifierNote: The queue id must exist in Queues.xml file
labelOptionalStringIs used to set the output message after executing maintenanceNote: 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 file Email.xml. You can see email definition for more information.

Email element in maintains has the following attributes:

AttributeUseTypeDescriptionValues
idRequiredStringEmail identifierNote: The email id must exist in Email.xml file
labelOptionalStringIs used to set the output message after executing maintenanceNote: 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 of Maintain.xml files.

Include target has the following attributes:

AttributeUseTypeDescriptionValues
nameRequiredStringTarget identifierNote: 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 SELECT statements.

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.