skip to main content

Handler types and modelling

Handler types #

As mentioned in Development Cycle, Livebase Handlers are divided into two groups: model-dependent ones, which depend on the classes and other elements defined in a model, and the default ones, which exist regardless of the model used.

Handler

Modelling Handlers are in turn divided into two families: Persistency Handlers and GUI Handlers:

  • Persistency Handlers: includes the SaveActionHandler, the ValidationHandler and the three DatabaseHandlers (DatabaseInsert, DatabaseUpdate, DatabaseDelete). They are used to manage the different steps in the process of saving/modifying an object and are called in the order we have listed them. The SaveActionHandler allows you to manage the fields of a write form, the ValidationHandler to perform a custom validation of a class instance, and finally the DatabaseHandler are in the commit phase of the database transaction.
  • GUI Handlers: includes the FormActionHandler, the ListActionHandler, the ObjectPrintHandler and the ListPrintHandler. They are triggered by custom events defined in one or more Application Schema; generally these events consist of a user clicking on a button to execute the plugin: the FormAction and the ObjectPrint are placed on the instance handler (the form), while the ListAction and the ListPrint are placed on the class manager (the Livetable or Editable). ActionHandlers are general-purpose, while PrintHandlers offer support for exporting the form/table content in a format suitable for printing.

The default handlers are the AuthenticationHandler, the LogoutHandler and the ScheduledTask).

Modelling Handlers #

To add a handler to a model class, from the Database Schema , open the Class menu (by right-clicking on the class header) and select the corresponding New handler from the available ones, as shown in the picture:

Des classMenu handlers

Once the type of Handler has been chosen we need to:

  • Type a name, which must be unique in the namespace of the class.
    A good practice is to use a name representative of the action we want to perform, e.g. sendEmail if the Handler will send an email.
  • For some Handlers (including the FormActionHandler) additional configuration is required in the Application Schema .
  • For some Handlers extra options are also available in the Service Handler context menu, accessible by right-clicking on the Handler from the Database Schema . [LINK]

Handlers and namespace #

Handlers defined on a class share a separate namespace from the attribute namespace. In the diagram they are listed in another list below the attribute list; for example, shown in figure there are three different Handlers on Class1.

Des handlers example

Handlers and application views #

Similarly to the other elements of the diagram - classes, attributes, relations- it is possible to enable/disable a Handler for a specific application view: to do so, just click on the Handler from the Application Schema to toggle its state, as illustrated in the tutorial (Define application views and user profiles). This allows you to choose in which application views to allow the use of a certain plugin on that class.

Des handlers example app schema

Persistency Handlers #

SaveActionHandler #

It is called whenever data entry is confirmed in the application and the save event occurs; there are two current scenarios:

  • In a form, click the Save button (or Confirm in the case of a part object) after filling in the fields for an object.
  • Click of the Save button on an Editable, after editing its contents by adding/editing/deleting lines.

The action will be executed before the data are validated and saved on the database; this allows to manage in writing the fields filled in by the user and eventually modify their content ’ for example, formatting the native attributes or adding information on the database and linking them to the created object by initializing default relationships.

The developer can specify the operations to be performed by the handler by implementing the doAction() method of the related class, and interacting with the context (SaveActionHandlerContext) which is its parameter.

SaveActionHandlerContext #

The entity can be accessed either in the pre-modified or current version, and in the latter case both the internal fields of the entity and those of any related objects can be written.

The handler can only return an empty result by calling none() on the result object offered by the context.

ValidationHandler #

It is called after the SaveActionHandler (if present on the same class) and before committing a transaction to the Database related to one of the operations (insert or update) on the instances of a specific class. This Handler allows you to implement custom validation logic for the class instance, with which you can control rules that cannot be expressed in the model (e.g., through restrictions on the domain of the attributes, Class warnings, or through rules whose specificity makes the low-code approach too onerous, like making a call to an external service to validate fields.

The developer defines the validation process by implementing the validate() method of the handler class, and interacting with the context (ValidationHandlerContext) that is its parameter.

ValidationHandlerContext #

The entity involved may be accessed in the previous and current versions, but only in read mode.

The handler must return a result indicating the success or failure of the custom validation. To do this, once you have the result, you must make one of the following calls:

  • success() : To report the success;
  • fail(msg)` : To report a negative result. This call must be provided with a string representing an error message, which will be displayed in a dialog box while the application runs.

Access to the set of Cloudlet locale values, as defined within the Designer, is also offered by invoking the getCloudletLocales() method.

Blocking ValidationHandler #

By default, the additional validation performed by a ValidationHandler is non-blocking: if the save action is not successfully validated, the application displays a warning allowing the user to confirm or deny it, similar to the non-blocking Class warning.

We can change this behaviour by adjusting the Blocking flag in the context menu accessible by right-clicking on the ValidationHandler: checking this option will cause validation to be blocked, and if validation is negative, the framework will reject the save action.

The context failure(msg) method has an optional boolean parameter, which allows you to override the behavior specified in the Designer in certain cases: a value of true will make the validation blocking, and a value of false will make it non-blocking.

DatabaseHandler #

For each transaction there is a specific variant of this Handler: DatabaseInsertHandler, DatabaseUpdateHandler and DatabaseDeleteHandler. Each is called before and after committing a transaction to the Database related to one of the operations (insert, update, delete) on instances of a specific class. In the case of the first two, this always happens after the ValidationHandler (if it is present on the same class). These handlers allow you to perform actions that depend on the content of a transaction, e.g. run a custom SQL query.

You can change the type of transaction calling the DatabaseHandler from the Change type item in the Handler’s context menu.

Each DatabaseHandler requires two methods to be implemented by the developer: beforeCommit(), to specify what to do before committing the transaction, and afterCommit(), for operations after the same commit. In the first case, the context offered is a TransactionalContext, and in the second case, a Context.

Execution contexts #

Entity read-only access is allowed, and depending on whether you are working before or after the commit, you may have visibility of the current (new) and/or previous (old) version:

Handler typeImplemented methodAccess
InsertbeforeCommitnew
InsertafterCommitnew
UpdatebeforeCommitnew/old
UpdateafterCommitnew
DeletebeforeCommitold
DeleteafterCommitNO

The only result that can be returned by a DatabaseHandler’s methods is a positive conclusion, which can be obtained by invoking the none() or reloadObjectData() methods on the result. The former performs no further operations, while the latter forces the update of the manipulated object form, without having to click the Update button inside the application.

Blocking DatabaseHandlers #

By default, DatabaseHandlers do not cause exceptions when they are not implemented. From the Service handler menu you can check the Implementation required option and force the application to request the execution of a Plugin that implements the corresponding Handler, blocking persistence on the DB if the Plugin is not present in the Cloudlet or if it is inactive.

Des service handler menu handlers

GUI Handlers #

FormActionHandler #

It is called when a custom event occurs in the form of an object. After creating it, you must then also define the event in the Form Layout Editor , in the application view for which the Handler is enabled. There are two ways to define the event:

  • Click on the exec plugin button. To add it, drag it into the form from the Buttons tab, select the Handler to invoke and click OK.
  • OnChange** event triggered by a form widget. To set this, right click on the desired widget ’ Set events,onChange and select the Handler.

Des form layout editor handler button

An Exec plugin button can be further customised by selecting it and editing its properties. From type we can choose which Handler to call again, and from enabledIf we can choose whether to display it exclusively in one of the two form modes (edit or view), or both.

Des form layout editor handler button properties

The button will appear in the generated application along with the other form fields.

App form formAction handlerButton

Unlike Persistency Handlers, which are triggered in a specific sequence, FormActionHandlers can perform their own sequence of actions at any time. These actions must be specified by implementing the doAction() method of the related class and interacting with the FormActionContext which is its parameter.

FormActionContext #

The Entity referenced by the form is accessible in the version being edited, both read and write. You can also access the session with the database, in its mutable version, with the getEntitySession() method offered by the context.

Additional features offered by the context are:

  • The ability to get information about the event that triggered the handler, via the getEventSource() method. This information includes the type of event (click on button or onChange) and the form field it is attached to;
  • Accessing the Cloudlet’s file storage via the getFileService() method;
  • Accessing a JSON of parameters passed by a client via the getHandlerCustomParams() method.

The results that can be returned by a FormActionHandler are:

  • none()` : a positive result that takes no further action;
  • download(file, fileName)` : orders the download of a file. Optionally you can also pass the name to save that file on the target filesystem;
  • preview(file, fileName)` : opens a new tab in the Cloudlet runtime browser, containing a preview of a file. From this tab you can decide whether to download the file, and again there is an optional parameter for specifying the name to save it with;
  • withMessage(msg) : displays a dialog containing the message passed as a parameter. This call must be followed by one specifying the severity level of the message:
    • info()` : simple information message, no error value;
    • warning()` : warning or error message, generally not blocking;
    • error()` : blocking error message.
  • withPayload(json)` : returns a JSON, specified as a string and passed as a parameter, to a client accessing the Cloudlet.

FormActionHandler and Form class #

The FormActionHandler service handler menu offers the Set form... command, which allows you to link a Form class to the class on which the Handler is defined.

Des handlers serviceHandlerMenu setFormClass

In the application, the useMyForm button will popup the myForm form from the desired position. This way the Handler inside Class1 will also have the context of myForm (all fields filled in with their values) available to it: this is achieved by calling getHandlerParams() on the FormActionHandler context.

A Form Class, like normal classes, can have FormActionHandlers attached to its buttons or onChange() events, in which case you can access the filled fields via the getEntity() method and the possible results are the same as a handler defined on other non-Form classes.

ListActionHandler #

It is similar to the FormActionHandler, but is called by clicking on a button on the Livetable of a class.

This allows you to perform block actions on objects of the class ’ e.g. modify a subset of selected objects or create new pre-configured objects.

App lt listAction handlerButton

We can configure it from the List layout editor of the class on which it is enabled in an application view. As we saw in Modeling with relationships, the editor is accessible in two ways:

  • By configuring the Livetable/Editable from the Management tab of the GUI widgets configurator of the source class (default layout).
  • Editing the properties of an Association manager within the Form layout editor of an associated class (overriding the default for that specific role).

When Handlers are present on the class, the additional Custom buttons area is shown on the editor. To add a button, click on the New button... button at the bottom right, select the Handler to be executed and click OK; it will appear in the Custom buttons column.

Des listLayoutEditor handlerButton

By right clicking on the button → Enable on’ we can choose its activation policy. In this way we can show the button dynamically only when a certain number of objects is selected, and hide it otherwise.

Des listLayoutEditor handlerButton properties

The button will appear in the generated application below the other buttons in the Livetable:

App lt listAction handlerButton

To specify the operations to be performed by the ListActionHandler, you need to implement the doAction() method of its interface, and interact with the ListActionContext that represents its parameter.

ListActionContext #

We can get a set of the Entities we have selected through the application, by means of the getSelectedEntities() method: all of them will be accessible in both read and write mode, in the current version. In addition, the handler context provides access to the mutable session with the database (getEntitySession() method), for performing CRUD operations on its contents.

As for a FormActionHandler on the single Entity, the ListActionHandler offers access to the Cloudlet file storage (method getFileService()), as well as to the JSON with parameters passed via client (method getHandlerCustomParams()). One difference with the former is the possibility to access the localised values, via the getCloudletLocales() method.

The doAction() method must return one of the following results:

  • none()`: a positive result that takes no further action;
  • download(file)`: orders the download of a file;
  • preview(file)`: opens a new tab in the Cloudlet runtime browser, containing a preview of a file. From this tab you can decide whether or not to download the file;
  • withMessage(msg)`: displays a dialog containing the message passed as a parameter. This call must be followed by a call specifying the severity level of the message:
    • info()`: simple information message, no error value;
    • warning()`: warning or error message, generally not blocking;
    • error()`: blocking error message.
  • showObjectDetail(id)`: opens the detail form for the object whose id was passed as a parameter.

ListActionHandler and Form class #

The context menu of the ListActionHandler also offers the command Set form..., which allows you to hook a Form class to the class on which the Handler is defined.

ObjectPrintHandler #

It is called up by clicking the Print button of an object of a specific class. This allows you to export the form content for printing in different formats.

For each class, it is possible to define multiple ObjectPrintHandlers: in this case, when the Print button is pressed, a menu will appear that will allow the user to choose the desired print type.

App form print handler button

The actions to be performed must be specified by implementing the print() method of the related interface. Access is offered to the ObjectPrintContext which is the parameter of this method.

ObjectPrintContext #

Read-only access to the Entity is permitted, and in the current version only. Session access to the database is not offered.

Access is offered to the localized values defined in the Cloudlet, via the getCloudletLocales() method.

The results returned by the Handler are:

  • download(file, fileName)`: orders the download of a file. Optionally you can also pass the name to save that file on the target filesystem. As an alternative to the file you can pass a reference to a stream or URI;
  • preview(file, fileName)`: opens a new tab in the Cloudlet runtime browser, containing a preview of a file. From this tab you can decide whether or not to download the file, and again there is an optional parameter for specifying a file name. As an alternative to the file, you can pass a reference to a stream or URI;
  • withMessage(msg)` : displays a dialog containing the message passed as a parameter. This call must be followed by one specifying the severity level of the message:
    • info()` : simple information message, no error value;
    • warning()` : warning or error message, generally not blocking;
    • error()` : blocking error message.

ListPrintHandler #

It is called by clicking on a print button on the Livetable of a specific class. It is similar to the ObjectPrintHandler and allows you to print the information associated with a subset of selected objects, or all objects in the table.

App lt print handler button

The actions to be performed are specified by implementing the print() method of the interface. It will offer access to the ListPrintContext which is the parameter of this method.

ListPrintContext #

It is possible to access only the session with the database, in its immutable version.

It is also possible to access localised values defined inside the Cloudlet, with the getCloudletLocales() method called on the handler context.

A ListPrintHandler admits the same results as an ObjectPrintHandler defined on the single object.

Default Handlers #

AuthenticationHandler #

It is called at the time of authentication of a Cloudlet member, i.e. when the user enters username and password and clicks the Login button. This information is passed to the AuthenticationHandler, which can perform an authentication with custom rules 'e.g. run additional checks on the Database or coordinate with an external service.

The developer must implement the authenticate() method of the SpiCloudletAuthenticationHandler interface, specifying the actions to perform at login time. The same method offers a parameter of type AuthenticationData, which contains information about the type of authentication that was performed.

LogoutHandler #

It is called after a click on the Logout button to perform a custom action at this point in the execution ’ for example, redirecting the browser to another page (especially useful if the generated application is linked to a custom front-end).

The developer must implement the logout() method of the SpiCloudletLogoutHandler interface, with the sequence of actions to execute at logout time. The context that is its parameter is a LogoutHandlerContext.

LogoutHandlerContext #

It offers the following utility methods:

  • getAuthenticationData()`: Gets the AuthenticationData structure mentioned in the previous section, which contains authentication information;
  • get__CloudletCurrentUser()`: Gets the information about the Cloudlet user who logged out.

The LogoutHandler must return a result specifying whether or not a redirect to another URL is needed. In the first case, you must call the none() method on the structure obtained by calling result(); in the second case, you must call the sendRedirect(url) method with the specification of the URL to redirect to.

ScheduledTask #

The ScheduledTasks can be used to schedule routines independently of events occurring on the application; for each task we can configure the frequency using a CRON expression (whose summary can be found here).

The developer must implement the run() method of the SpiCloudletScheduledTask interface, and decorate the defined class with the @CloudletScheduledTask annotation. In the annotation, specify the CRON expression that defines the run frequency. The run() method is equivalent to a procedure, therefore it must not return any results.