. . .

Development Basics

This page gives you a short introduction about the basics of developing modules with ApiOmat. You'll get a simple introduction of the development workflow and a brief overview about the relevant parts of the Native Module SDK. The links which are contained on this page to further topics will help you to get deeper into module development.

Workflow

In general you can achieve a new Native Module in five basic steps:

  1. Create a new module and the classes via Dashboard

  2. Download the Native Module SDK or check out the Native Module code from the Git repository (depending on how you created the module)

  3. Import the SDK into your development environment

  4. Insert the logic to be executed in the backend by using hook classes.

  5. Upload the modified module / push the changes to the Git repository (depending on how you created the module)

About the Native Module SDK

As the above guides you to a working Native Module, there are some further technical aspects you should know about.

Package structure

The package com.apiomat.nativemodules includes all necessary Java classes. You can find interfaces, annotations and utility classes that are needed for execution at this package level .

The package com.apiomat.nativemodule.basics contains the classes User and Role, which do exist in each module. The class User represents a user of an app, which can be used to authorize. The class Role describes a role that an user of your app can take. You can restrict the access to all objects of specific classes (class level access control) or even directly to specific objects (object level access control). You can find further information about this topic on our page about data access security .

You can find the non-generic classes of your module on the same level as the basics package. The full package name is always com.apiomat.nativemodule.<modulename> where the <modulename> is always the lower-cased name of your module. You can find more informations about the classes that are contained there in the chapter about "user-defined classes" below.

Another package is com.apiomat.nativemodules.interfaces.dmap, which contains classes to handle distributed maps.

ApiOmat generates a bunch of packages and classes which can be adjusted by you. It is also still possible for you to benefit from common architecture patterns, as you would do in ordinary desktop development. You can put additional packages and classes in the src folder and call them from within the hook methods. ApiOmat can then access the functionality after uploading.

SDK-Properties

The properties file sdk.properties holds all data that is necessary to automatically up- or download an updated SDK containing changes to the class structure to or from ApiOmat.

You have to adjust the following values initially:

  • password - the password of the module owner

  • merge - "true" (default), if the downloaded package should not only include generated classes and utility classes, but also customized and self-made classes. (e.g. hooks, REST Endpoints, ..)

  • update - "true", if local changes to model classes should be recognized by ApiOmat and thus be reflected in the class structure
    - "overwrite"(default), if an attribute has been modified or deleted locally and these changes should be repeated to the server
    - "false", for none of the above (or just comment out the update setting)

Libraries

The folder lib contains all libraries that are necessary for this project. They include libraries like "swagger-annotations" for the REST endpoints and other ApiOmat modules, as well as the currently developed module uses other modules (e.g. the SAML module for SSO authentication).

You can add other libraries that are neccessary for the module here as well. You should note, that libraries which are already included in YAMBAS (e.g. Apache HTTP Client) must have the same version number as the corresponding YAMBAS libraries!

You can retrieve a list of all libraries that YAMBAS uses through calling <BasisURL>/yambas/rest with authentication credentials of the Super Admin, for example:

curl http://localhost:8080/yambas/rest -u apinaut@apiomat.com:secret -H "Accept: application/json"


Module main class

First of all, there is a module main class with the same name as the module. It is always located in the package com.apiomat.nativemodule.<modulename> and must be provided to upload a module.

This class provides information about the module itself (like the description), the configuration of the module, methods that handle the lifecycle of a module and contains fields over which you can invoke module-specific methods (like logging or handling of objects).

Module Annotation

The module main class must contain the Module annotation as class annotation. It indicates YAMBAS (beside the mentioned naming convention) that this file is the main class of the module.

The annotation holds additional information about the module, like the description, the category of the module, the documentation URL, all modules that this module uses and the security permissions this module needs (which is only necessary if you're running a white label installation).

If you specify a module description, category and/or documentation, these information will be displayed for example in the module market of the Dashboard. If you add your module to a backend and your module uses other modules that were not already added to the backend before, ApiOmat will automatically append these modules to your backend, too.

Example for a module annotation
@Module( description="Example Module", category ="Communication", documentationURL = "/docs/example-module.html", usedModules={"AnotherExampleModule", "SMTP"}, securityPermissions = {} )


Static helper fields

Each module main class contains two static fields by default.

The first field is of the type IStaticMethods and is named AOM. It is the main entrance point to handle objects. It provides methods to create objects, find objects by its id, foreignId, query or access token. It allows you to log information or errors, lets you throw exceptions correctly or handle distributed maps. You will use this interface very frequently.

The second field is of the type IApplicationConfigProxy which is named APP_CONFIG_PROXY and allows access to the module configuration with its only method getConfigValue. Read the next paragraph to get more information about the module configuration.

Module Configuration

Of course it is possible to define configuration parameters for your own module. This is done by defining a static String variable and adding the NativeModuleConfig annotation in the module main class:

@NativeModuleConfig( datatype = Type.TEXT, example = "http://www.mywebsite.com/api", title = "URL", info = "URL endpoint my website", key = "url", order = 1, notifyAllNodes=false )
public static String URL = "mymodule_url";


NativeModuleConfig provides several data types, an example value, a title and a description for a specific configuration parameter. You can modify display order of the several parameters in the module configuration screen, as shown below, by specifying the order field.

The field notifyAllNodes can be used to indicate that a change of this configuration value will be reflected on all nodes of your ApiOmat cluster. By default, only the node where the request for the configuration change arrives will execute the onConfigChanged hook for this value (see next part).

As soon as the configuration parameters are added to the module main class and the module has been uploaded, the parameters are displayed by if you hover over the module name in the left bar of the Dashboard, until a context menu opens. There you can choose the "Configuration" entry to open the menu. Also, m odule configurations are specified each time the module is added to a backend using the Dashboard, as shown in this example of the configuration for the Evalanche module:

images/download/attachments/10716484/evalancheConfig.png

You can get the current value of a configuration entry of one backend in the module code by calling the getConfigValue method of the APP_CONFIG_PROXY field in the module main class:

<ModuleName>.APP_CONFIG_PROXY.getConfigValue( <ModuleName>.<ConfigName>, appName, system );

Life cycle methods of a module

The main module initially contains the following methods which reflect hooks for events that occur during the life cycle of a module:

public void onDeploy( )
public void onUndeploy( )
public void onConfigChanged( String appName, String configKey , String system)
public void onCronHourly( final String appName, final String system )
public void onCronDaily( final String appName, final String system )
public void onCronWeekly( final String appName, final String system )
public void onCronMonthly( final String appName, final String system )
public void onModuleAttach( final String appName, final com.apiomat.nativemodule.Request request )
public AbstractRestResource getSpecificRestResource( UriInfo uriInfo, HttpServletRequest servletRequest,SecurityContext securityContext, Request wsRequest )



We will next describe each method and its purpose. The onDeploy and onUndeploy methods are hooks which are called each time a module is deployed or undeployed. The onDeploy is called each time the module is uploaded using the upload or if its moduleStatus is manually changed to DEPLOYED . The corresponding onUndeploy will be executed if the status of the module is set to UNDEPLOYED . This method is also called if a redeploy (upload of a module again, as the old version of the module will be undeployed and the newly uploaded version is deployed ) is performed and is executed before the onDeploy takes place.
The onConfigChanged hook informs the module about changed configuration values in a backend. Depending on the notifyAllNodes flag in the NativeModuleConfig annotation (see the paragraph above) of the specific configuration value, this hook is either executed only on one or on all nodes of your ApiOmat cluster. This method is called on any change to the current configuration and receives the app name as well as the changed key through its parameter list. This means that onConfigChanged is called once for every changed configuration parameter. There are four methods where you can implement cron-like tasks. These methods are executed automatically at a specific time. Typically, things like periodic sync or cleanup tasks can be put in these methods. The methods are executed as follows:

  • onCronHourly: every full hour (e.g. 8pm, 9pm, 10pm,...)

  • onCronDaily: every day at 3am

  • onCronWeekly: every week on Mondays, 3am

  • onCronMonthly: on every first day of the month, 3am

There is also an onModuleAttach hook which simply gets invoked, if your module is attached to a backend.

You can specify a class that should receive custom REST requests in the method getSpecificRestResource. An example class for that is contained in every module with the name RestClass.java. Thus, it is possible to provide an entirely custom-tailored REST interface to implement OAuth callbacks for example. Please see this separate article to get more information.

Notes about statics in module main

Since the module main class can internally be instantiated multiple times, it should be noted that when using the key word "static". Static variables will share their values with every backend that uses the respective module. If a backend "A" changes a static variable of a module class, this new value will be visible and editable from backend "B", too.

This behaviour is not intended in most cases and can be avoided by storing values inside a map with the respective app names as keys. Instead of

static Connection con;


you could use

static Map<String, Connection> con;


User-defined classes

Any class that you define for your module through the Dashboard will generate a new corresponding Java class that you can receive when you download the latest version of the native module SDK. The class will contain any attributes that you defined in the Dashboard. As mentioned above, these classes will be placed into the package com.apiomat.nativemodule.<modulename>.

Each of these model classes will have an Model annotation to indicate that the given class is an ApiOmat based model class. The model annotation holds information about the related hook-classes, the transient, global and invisible state of the class and it's allowed and required roles.

Example for a Module annotation
@Model( moduleName = "TestModule",
hooksClassNameTransient = "com.apiomat.nativemodule.test23.TestClassHooksTransient",
hooksClassNameNonTransient = "com.apiomat.nativemodule.testmodule.TestClassHooksNonTransient",
isTransient = false, isGlobal = false, isInvisible = false,
requiredUserRoleCreate=UserRole.User, requiredUserRoleRead=UserRole.User,
requiredUserRoleWrite=UserRole.Owner, restrictResourceAccess=false,
allowedRolesCreate={"Role1,Role2"}, allowedRolesRead={"Role1,Role3"}, allowedRolesWrite={"Role3"}, allowedRolesGrant={})


This generated class cannot be changed although changes to the data model can be done through the Dashboard and downloaded afterwards using the native module download. Unchanged files will be overwritten while doing so. However, it is possible to add new attributes directly in the source code of a user-defined class. They will be added in ApiOmat automatically as soon as the updated source code is uploaded. The SDK can be downloaded afterwards if it isn't required to define getters and setters oneself since existing classes will be replaced by generated ones.

In order for changes in these classes to take effect after uploading, the update flag in the sdk.properties file must be set with true. If existing attributes are to be deleted or modified as well, the flag has to be set to overwrite. If you don't want any of this, set it to false or comment it out.

References can be annotated with the EmbeddedDocument annotation to mark them as Embedded Documents .

@EmbeddedDocument private Address address = null;


* link only available in Enterprise Documentation