public abstract class TableTrigger extends Object
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.
setParam1(...)
and
setParam2(...)
);setup(TriggerSetupContext)
is called on the new instance.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.
Table triggers are not invoked in the following contexts:
ProcedureContext.setTriggerActivation(false)
.
ProcedureContext.doMergeToParent(com.onwbp.adaptation.AdaptationHome)
).
ProcedureContext.doImportArchive(ArchiveImportSpec)
).
ProcedureContext.doCopy(com.onwbp.adaptation.Adaptation)
).
When a record operation is performed, the sequence is the following:
handleBefore<Operation>
is invoked,handleAfter<Operation>
is invoked.Each trigger method can impact any system, persistent or not, including the EBX® repository. The main cases are outlined below:
ProcedureContext
.
Procedure
.
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
:
table1
handleBeforeModify
in table1
table1
handleAfterModify
in table1
table2
handleBeforeCreate
in table2
table2
handleAfterCreate
in table2
table2
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.
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.
Procedure.execute(ProcedureContext)
Constructor and Description |
---|
TableTrigger() |
Modifier and Type | Method and Description |
---|---|
void |
handleAfterCreate(AfterCreateOccurrenceContext aContext)
This method is called after the creation of a record.
|
void |
handleAfterDelete(AfterDeleteOccurrenceContext aContext)
This method is called after deleting a record.
|
void |
handleAfterModify(AfterModifyOccurrenceContext aContext)
This method is called after the modification of a record.
|
void |
handleBeforeCreate(BeforeCreateOccurrenceContext aContext)
This method is called before the creation of a record.
|
void |
handleBeforeDelete(BeforeDeleteOccurrenceContext aContext)
This method is called before deleting a record.
|
void |
handleBeforeModify(BeforeModifyOccurrenceContext aContext)
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 |
handleBeforeTransactionCommit(BeforeTransactionCommitContext aContext)
This method is called before committing the updates which happened during procedure execution.
|
void |
handleNewContext(NewTransientOccurrenceContext aContext)
This method is called when a transient record context is created.
|
abstract void |
setup(TriggerSetupContext aContext)
Checks and prepares this instance when the data model is loaded.
|
public abstract void setup(TriggerSetupContext aContext)
public void handleNewContext(NewTransientOccurrenceContext aContext)
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:
ProcedureContext.setTriggerActivation(boolean)
;ProcedureContext.getContext(boolean, ValueContextForUpdate, AdaptationTable)
;The default implementation of this method does nothing.
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:
public void handleBeforeCreate(BeforeCreateOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
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:
mayCreateRoot
and mayCreateOverwriting
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.
OperationException
- to be thrown as a functional guard, or when an
unexpected exception occurs.
As a consequence, the whole transaction is always aborted.handleNewContext(NewTransientOccurrenceContext)
,
handleAfterCreate(AfterCreateOccurrenceContext)
public void handleAfterCreate(AfterCreateOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
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 in
handleBeforeCreate
.handleBeforeCreate(BeforeCreateOccurrenceContext)
public void handleBeforeModify(BeforeModifyOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
OperationException
- to be thrown as a functional guard, or when an
unexpected exception occurs.
As a consequence, the whole transaction is always aborted.handleAfterModify(AfterModifyOccurrenceContext)
public void handleAfterModify(AfterModifyOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
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 in
handleBeforeModify
.handleBeforeModify(BeforeModifyOccurrenceContext)
public void handleBeforeDelete(BeforeDeleteOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
OperationException
- to be thrown as a functional guard, or when an
unexpected exception occurs.
As a consequence, the whole transaction is always aborted.handleAfterDelete(AfterDeleteOccurrenceContext)
public void handleAfterDelete(AfterDeleteOccurrenceContext aContext) throws OperationException
This method will not be called if ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
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 in
handleBeforeDelete
.handleBeforeDelete(BeforeDeleteOccurrenceContext)
public void handleBeforeTransactionCommit(BeforeTransactionCommitContext aContext) throws OperationException
ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
The default implementation does nothing.
OperationException
- when an exception occurs;
as a consequence, the current transaction is aborted.public void handleBeforeTransactionCancel(BeforeTransactionCancelContext handlingContext)
ProcedureContext.setTriggerActivation(boolean)
has been set to false
.
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
the kernel
category, then the remainder of the cancel process
is executed (including other potential triggers handleBeforeTransactionCancel
).