Error handling
When code is written to be executed through an event, errors and warnings may need to be handled, for example, an erroneous value entered in a field.
This document describes how to trigger an error or a warning message to send to the user. Additional errors methods have been added in update 9.
The management of error gravity is based on a numeric value called status. Available statuses are defined by constant values (in increasing order, which mean that you can test the fact that the status is greater or equal than [V]CST_ERROR
, for example):
Constant | Meaning |
[V]CST_ASUCCESS | The requested operation has been successfully performed. |
[V]CST_AINFO | Information message: no error occurs. |
[V]CST_AWARNING | Warning message: an unusual set of values has been entered. The system sends a warning and allows you to modify the data entered. |
[V]CST_AERROR | An error occurred. The data entered must be modified to execute the operation requested. |
[V]CST_AFATAL | A fatal error occurred. A restart of the complete process is necessary. |
Two standard methods available on the classes allow to throw errors. One allows to give an additional category, the other remains for historical reasons. These methods can be invoked several times when more than one error occurs.
INTEGER_VAL=fmet this.ASETERRORCAT (PROPERTY,MESSAGE, ERROR_TYPE, CATEGORY)INTEGER_VAL=fmet this.ASETERROR(PROPERTY, MESSAGE, ERROR_TYPE)
Parameter | Use |
---|---|
PROPERTY | Code of the property in which the error occurs. If empty, the error is general and not linked to a property. |
MESSAGE | String value containing the error message (in the language of the user). |
ERROR_TYPE | Status (see chapter 1 above).[V]CST_AOK must not be used with ASETERROR error throwing method (if the user interface is implied, it returns an error without a message). |
CATEGORY | An integer value that contains an error category. This can freely be defined by application developers. |
On every instance, we will provide a set of methods:
INTEGER_VAL=fmet this.AGETMAXERRORALL()INTEGER_VAL=fmet this.AGETMAXERROR(PROPERTY) INTEGER_VAL=fmet this.AGETMAXERRORTXT(SEARCH_TYPE, PROPERTY, ERROR_TYPE, PROPERTY_LABEL, MESSAGE,CATEGORY,ENVIRONMENT)
Parameter | Description |
---|---|
Value Integer SEARCH_TYPE | Contains one of the following valuesCST_ACURRENT : if only the errors from the current instance are extractedCST_ALL :if the nested sub-instance and the copied instance are extracted |
Value Char PROPERTY | Property concerned only (if not empty and if ERR_LOCAL is CST_ACURRENT ) |
Value Integer ERROR_TYPE | Can have the following values:CST_ALL : returns the highest error in the instance and nested sub-instancesCST_ACURRENT : returns the highest error in the current instance only. |
Variable Char PROPERTY_LABEL | Label associated to the property if PROPERTY returned |
Variable Char MESSAGE | Error message |
Variable Integer CATEGORY | Category (given by the developer when throwing the error) |
Variable Char ENVIRONMENT | Environment code given by developer when the error is transferred (empty if the error was not copied from another instance) |
Accessing to the complete error stack is performed with the following methods:
INTEGER_VAL=fmet this.ASEARCHINFOS(SEARCH_TYPE, PROPERTY, ERROR_TYPE, SEL_TYPE)
This first method initializes a temporary error storage structure. It returns an integer value that is the first error index (this value is 0 if no errors have been found). The parameters are the following:Parameter | Definition |
---|---|
Value Integer SEARCH_TYPE | Contains one of the following valuesCST_ACURRENT : if only the errors from the current instance are extractedCST_ALL :if the nested sub-instance and the copied instance are extracted |
Value Char PROPERTY | Property concerned only (if not empty and if ERR_LOCAL is CST_ACURRENT ) |
Value Integer ERROR_TYPE | Filter on status(CST_ASUCCESS , CST_AINFO , CST_AWARNING , CST_AERROR , CST_AFATAL ) |
Value Integer SEL_TYPE | Comparizon operator on status ([V]CST_ALOWER =less or equal to ASTATUS , [V]CST_AEQUAL =equal to ASTATUS , [V]CST_AGREATER =greater than ASTATUS ) |
INTEGER_VAL=fmet this.AGETNEXTINFOS(ERROR_TYPE, PROPERTY, PROPERTY_LABEL, MESSAGE, CATEGORY, ENVIRONMENT)
This second method returns the errors in the chronological order and fills the corresponding parameters. When the last error has been sent back, 0 is returned and the temporary error structure is cleaned up.The parameters are the following:
Parameter | Definition |
---|---|
Variable Integer ERROR_TYPE | status error (CST_ASUCCESS , CST_AINFO , CST_AWARNING , CST_AERROR or CST_AFATAL ) |
Variable Char PROPERTY | Corresponding property if applicable |
Variable Char PROPERTY_LABEL | Property description if applicable |
Variable Char MESSAGE | Error message |
Variable Integer CATEGORY | Category (given by the developer when throwing the error) |
Variable Char ENVIRONMENT | Environment code given by developer when the error is transferred (empty if the error was not copied from another instance) |
$ERROR_LOG_WRITE# Instantiate a class to generate the logLocal Instance MYLOG Using C_ALOGMYLOG=NewInstance C_ALOG AllocGroup Null# Open the log fileLocal Integer OKOK=fmet MYLOG.ABEGINLOG("Error dump")# Fill the error structureLocal Integer IF_ERRORLocal Integer ERR_STAT, ERR_CATLocal Char ERR_PROP(250), ERR_LAB(250), ERR_MESS(250), ERR_ENV(250)IF_ERROR= fmet this.ASEARCHINFOS([V]CST_ALL,"",[V]CST_AINFO,[V]CST_AGREATER)# Display an error header logIf IF_ERROR<>[V]CST_AOKOK=fmet MYLOG.APUTLINE("Error stack generated by"-this.ACTX.USER-"at"-num$(timestamp$))OK=fmet MYLOG.APUTLINE(string$(80,"-"))Endif# Loop as long as errors are encounteredWhile IF_ERROR=[V]CST_AOKOK=fmet MYLOG.APUTLINE("Index"-num$(IF_ERROR)+":")IF_ERROR=fmet this.AGETNEXTINFOS(ERR_STAT, ERR_PROP, ERR_LAB, ERR_MESS, ERR_CAT, ERR_ENV)OK=fmet MYLOG.APUTLINE(" Status="+string$(ERR_STAT=[V]CST_AERROR,"Error")& +string$(ERR_STAT=[V]CST_AWARNING,"Warning")& +string$(ERR_STAT=[V]CST_AFATAL,"Fatal error"))OK=fmet MYLOG.APUTLINE(" Message="+ERR_MES)IF ERR_PROP<>""OK=fmet MYLOG.APUTLINE(" on property="+ERR_PROP+string$(ERR_LAB<>"","("+ERR_LAB+")"))EndifIF ERR_CAT<>0OK=fmet MYLOG.APUTLINE(" application category="+num$(ERR_CAT))EndifIF ERR_ENV<>""OK=fmet MYLOG.APUTLINE(" origin environment="+ERR_ENV)EndifWendOK=fmet MYLOG.AENDLOG()FreeGroup MYLOGReturn
INTEGER_VAL=fmet this.ADELETERROR(PROPERTY)INTEGER_VAL=fmet this.ADELETERRORALL()
Parameter | Definition |
---|---|
Value Char PROPERTY | Property on which the error must be deleted |
This method copies the error structures from the instance given as parameters to the error structure associated to this.
The environnement string allows to give a context:
INTEGER_VALUE=fmet this.AGETERRORSFROM(INSTANCE,ENVIRONMENT)
INSTANCE
is the instance from which the errors are copiedENVIRONMENT
is a character value given by the developer to indicate the origin of a nested error.This variable is available on all the events, whether this
is available or not. The value range is the same as the status values used by the ASETERROR method.
Setting this variable to [V]CST_AERROR
or [V]CST_AFATAL
is important when an error occurs because these values are tested by the supervisor layer on a return from an event code.
If an error is reported, the supervisor behaves as follows:
Type of event | Event Codes | Behavior |
---|---|---|
CRUD operation events | AINSERT,AREAD,AUPDATE,ADELETE | The database update should not have been performed. |
Properties events | INIT,GET,CONTROL,PROPAGATE | The event failed. If this happens during an input, the error will be displayed. If it happens on control at the final stage before the database updates, the updates will not be triggered, but the controls will continue on every Property. A complete list of the errors will be generated. |
CRUD control events | AINSERT_CONTROL_BEFORE,AINSERT_CONTROL_AFTER,ADELETE_CONTROL_BEFORE,ADELETE_CONTROL_AFTER,AUPDATE_CONTROL_BEFORE,AUPDATE_CONTROL_AFTER | The control failed. The operation 'Update operation' will not be performed (the control is not fulfilled). |
CRUD update events | AINSERT_BEFORE,AINSERT_AFTER,ADELETE_BEFORE,ADELETE_AFTER,AUPDATE_BEFORE,AUPDATE_AFTER | An error occurred in the transaction. The corresponding rollback operation will be executed. |
CRUD error handling events | AINSERT_ROLLBACK,ADELETE_ROLLBACK,AUPDATE_ROLLBACK | An error occurred during the rollback operation. |
When errors or warnings are triggered while using these methods, the result is the following:
ASTATUS
code is [V]CST_AOK
, nothing occurs.ASTATUS
code is [V]CST_ASUCCESS
, a message can be transmitted to the user interface.ASTATUS
code is [V]CST_AINFO
or [V]CST_AWARNING
, the message is considered an informational or a warning message.ASTATUS
code is [V]CST_AERROR
or [V]CST_AFATAL
, the message is considered an error message.The supervisor layer considers that an error occurred during a class operation or method if ASTATUS returns a value of [V]CST_AERROR
or [V]CST_AFATAL
.
The warning or error messages updated by these methods will be displayed if a user's interface is involved. For example, if an error occurs during data entry, the error is displayed on the top of the screen with a link that brings the cursor to the Property field where the error was found.
If no user interface is involved, the development partner calling a method that returns errors can manage them in their own code or write them in a log file.
The following principles must be followed:
The following principles must be followed:
this.ASETERROR()
method must be used to set the message error. The property code must be filled if the error is linked to a Property.Every method and operation returns a value. This can be used either for returning a result or for returning an error code.
The this.ASETERROR()
method must be used to return an error. The value returned by the operation or method (ARET_VALUE
) must be assigned with the right value chosen when an error is encountered.
Local Integer RETURN_VALUERETURN_VALUE=this.AREAD(KEY)If RETURN_VALUE > [V]CST_AWARNING# An error occurredEnd RETURN_VALUEElse # The program continues...Endif
This code is called in a control event on a property that cannot be increased (a warning is sent if the amount is decreased by more than 10%).
# Note : no need to assign [L]ASTATUS=[V]CST_AOK if no error (done by default)Local Decimal DECR_PERCENTIf this.AMOUNT>this.snapshot.AMOUNT[L]ASTATUS=fmet this.ASETERROR("AMOUNT","Amount cannot be > "-num$(this.snapshot.AMOUNT),[V]CST_AERROR)ElseDECR_PERCENT=100*(this.snapshot.AMOUNT-this.AMOUNT)/(this.snapshot.AMOUNT+(this.snapshot.AMOUNT=0))If DECR_PERCENT>=10[L]ASTATUS=fmet this.ASETERROR("AMOUNT","Amount decreased by"-num$(int(DECR_PERCENT))-"%",[V]CST_AWARNING)EndifEndifReturn