Class TableTrigger
- Direct Known Subclasses:
BuiltInTrigger_launchWorkflow
Definition in the data model
The trigger must be declared under the element
xs:annotation/xs:appinfo
:
where<osd:trigger class="com.foo.MyTableTrigger" />
com.foo.MyTableTrigger
is
the fully qualified name of the class implementing this interface.
It is also possible to set additional JavaBean properties:
where<osd:trigger class="com.foo.MyTableTrigger"> <param1>...</param1> <param2>...</param2> </osd:trigger>
param1
and param2
are JavaBean properties of the specified class.
For more information, see the JavaBean specification.
Life cycle
- When the data model is loaded:
- the specified class is instantiated through its default constructor and the JavaBean property
setters are called (in the example above,
setParam1(...)
andsetParam2(...)
); - the method
setup(TriggerSetupContext)
is called on the new instance.
- the specified class is instantiated through its default constructor and the JavaBean property
setters are called (in the example above,
- During the operational phase: the methods
handle...
are called every time the associated operation is executed.
If several operations are defined for the same table, they are not executed in any particular order.
Restrictions
Table triggers are not invoked in the following contexts:
-
If triggers have been explicitly deactivated using the method
ProcedureContext.setTriggerActivation(false)
. -
In the context of a merge operation (see
ProcedureContext.doMergeToParent(com.onwbp.adaptation.AdaptationHome)
). -
In the context of an archive import (see
ProcedureContext.doImportArchive(ArchiveImportSpec)
). -
In the context of a dataset copy (see
ProcedureContext.doCopy(com.onwbp.adaptation.Adaptation)
).
Transaction Management
When a record operation is performed, the sequence is the following:
- the method
handleBefore<Operation>
is invoked, - the core record operation is performed (Create, Modify or Delete),
- the method
handleAfter<Operation>
is invoked.
Each trigger method can impact any system, persistent or not, including the EBX® repository. The main cases are outlined below:
-
the trigger modifies the same dataspace, in which case it must be
performed in the same transaction and use the same
ProcedureContext
. -
the trigger modifies another dataspace in the same EBX® repository, in which case
it must be performed in another
Procedure
. - the trigger modifies an external system, for example a registry in the Java memory, an RDBMS or a file system.
CAUTION: in the latter two cases, the system integrity cannot be fully
ensured in various cases, for example a sudden server shutdown. Consequently, the system must
be carefully designed so as to support such degraded situations. At least, for cases where
a Java exception has been thrown during the transaction, the method
handleBeforeTransactionCancel(BeforeTransactionCancelContext)
can be implemented to rollback the modifications done in the other dataspace or
in the other system.
During a single transaction (the first case described above), it is possible to perform
a sequence of nested updates. In the following example,
table1
has an afterModify
trigger which performs a record creation
in table2
:
- Start: Modify a record of
table1
handleBeforeModify
intable1
- Core record modification in
table1
handleAfterModify
intable1
- Start: Create record in
table2
handleBeforeCreate
intable2
- Core record creation in
table2
handleAfterCreate
intable2
- End: Create record in
table2
- Start: Create record in
- End: Modify a record of
table1
Known Limitation: A "before trigger" only allows updating the current record content
(no access to ProcedureContext
is provided).
If, at this point, more advanced updates are necessary, a specific service should be used instead of triggers.
Functional guard and exceptions
In the context of a method handleBefore...
, it is possible to
implement a guard by throwing an OperationException
if
some functional conditions on the data are not satisfied. This will cancel
the current transaction.
Throwing an OperationException
instead of a RuntimeException
provides the end-user with the benefit of a well-localizable and a more user-friendly error message,
when the error happens in the context of the user interface
(in contrast, this behavior does not apply to
handleBeforeTransactionCancel
).
In all cases, the current transaction is aborted.
Note: In further detail, if a ProcedureContext
raises an exception, any
preceding updates made on the repository during nested update executions
are first cancelled before the corresponding update method
catches the exception. This additional feature is for ensuring
that the repository and cache remain consistent, even if the corresponding
update method catches the exception.
- See Also:
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid
This method is called after the creation of a record.void
This method is called after deleting a record.void
This method is called after the modification of a record.void
This method is called before the creation of a record.void
This method is called before deleting a record.void
This method is called before the modification of a record.void
handleBeforeTransactionCancel
(BeforeTransactionCancelContext handlingContext) This method is called whenever a transaction has updated the associated table, and this transaction gets cancelled due to an exception.void
This method is called before committing the updates which happened during procedure execution.void
This method is called when a transient record context is created.abstract void
setup
(TriggerSetupContext aContext) This method is called when the data model is loaded, to check that this rule is consistent with the data model that defines it and to prepare this instance.
-
Constructor Details
-
TableTrigger
public TableTrigger()
-
-
Method Details
-
setup
This method is called when the data model is loaded, to check that this rule is consistent with the data model that defines it and to prepare this instance.Do note that during this step, all models may not be properly loaded. Thus, the repository should not be accessed during this step.
-
handleNewContext
This method is called when a transient record context is created. A transient record context contains temporary values used when creating a new record or when duplicating an existing one. This method gives the opportunity to add specific values to this context. When duplicating an existing record, it is called just after copying the values. Make sure that this method does not unintentionally override values.For the user interface, this method is called whenever the user uses the record 'Create' or 'Duplicate' action, and before the form is displayed, so that the form to submit has some fields with values preset by the trigger, if any. This method is not called in the following cases:
- When importing from XML or CSV;
- If triggers have been disabled using the method
ProcedureContext.setTriggerActivation(boolean)
; - If triggers have been locally disabled by setting the corresponding parameter in the method
ProcedureContext.getContext(boolean, ValueContextForUpdate, AdaptationTable)
;
The default implementation of this method does nothing.
Duplicating a record with read-only or hidden fields
If the method is invoked in the context of a record duplication, every read-only or hidden fields will be reset to their default value (or to
null
if no default value is set) after this method is called. This is to avoid triggering a node permission exception on submit.Should a node be duplicated regardless of permissions, it is possible to grant special privileges using
ValueContextForUpdate.setPrivilegeForNode(com.orchestranetworks.schema.Path)
. When using this method, it is important to note that:- this privilege will last until the create operation is finished and the record persisted.
- this privilege will not apply to the UI, in which the node display will always depend on the node permission.
-
handleBeforeCreate
This method is called before the creation of a record.This method will not be called if
ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
Limitations
It is important to note that this method can also provide values for primary key field(s). As a consequence, this method is called before each of three important internal checks:
- Before the internal check for primary key completeness;
- Before the internal check for record uniqueness;
- Before the internal permissions checks (the primary key must be complete so
that the data model properties
mayCreateRoot
andmayCreateOverwriting
can be evaluated).
Implementations of this method must be aware that the primary key may be incomplete or inconsistent, in which case the transaction will be aborted.
- Throws:
OperationException
- to be thrown as a functional guard, or when an unexpected exception occurs. As a consequence, the whole transaction is always aborted.- See Also:
-
handleAfterCreate
This method is called after the creation of a record. It gives the opportunity to notify a third-party system.This method will not be called if
ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- to be thrown only when an unexpected exception occurs. As a consequence, the whole transaction is always aborted. For a functional guard, it is strongly recommended to implement it inhandleBeforeCreate
.- See Also:
-
handleBeforeModify
This method is called before the modification of a record.This method will not be called if
If no modification to the initial record content takes place, this trigger will not be executed.ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- to be thrown as a functional guard, or when an unexpected exception occurs. As a consequence, the whole transaction is always aborted.- See Also:
-
handleAfterModify
This method is called after the modification of a record. It gives the opportunity to notify a third-party system.This method will not be called if
If no modification to the initial record content takes place, this trigger will not be executed.ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- to be thrown only when an unexpected exception occurs. As a consequence, the whole transaction is always aborted. For a functional guard, it is strongly recommended to implement it inhandleBeforeModify
.- See Also:
-
handleBeforeDelete
This method is called before deleting a record.This method will not be called if
ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- to be thrown as a functional guard, or when an unexpected exception occurs. As a consequence, the whole transaction is always aborted.- See Also:
-
handleAfterDelete
This method is called after deleting a record.This method will not be called if
ProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- to be thrown only when an unexpected exception occurs. As a consequence, the whole transaction is always aborted. For a functional guard, it is strongly recommended to implement it inhandleBeforeDelete
.- See Also:
-
handleBeforeTransactionCommit
public void handleBeforeTransactionCommit(BeforeTransactionCommitContext aContext) throws OperationException This method is called before committing the updates which happened during procedure execution. This method is called even ifProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
- Throws:
OperationException
- when an exception occurs; as a consequence, the current transaction is aborted.- See Also:
-
handleBeforeTransactionCancel
This method is called whenever a transaction has updated the associated table, and this transaction gets cancelled due to an exception. This method is invoked even ifProcedureContext.setTriggerActivation(boolean)
has been set tofalse
.The default implementation does nothing.
If the execution of this method itself throws a
Throwable
, it is caught by the caller method, an error message with the stack trace is logged into thekernel
category, then the remainder of the cancel process is executed (including other potential triggershandleBeforeTransactionCancel
).
-