Creating your own Automation Action

You can create your own Automation Action.

Conditions:

  • The new Automation Action class must implement the "Action" interface.
  • The new Automation Action class must be declared in the package "com.openkm.plugin.automation.action".
  • The new Automation Action class must be annotated with "@PluginImplementation".
  • The new Automation Action class must extend "BasePlugin".

Automation Action interface:

package com.openkm.plugin.automation;

import com.openkm.db.bean.AutomationRule.EnumEvents;
import net.xeoh.plugins.base.Plugin;

import java.util.List;
import java.util.Map;

public interface Action extends Plugin {

    void executePre(Map<String, Object> env, Object... params) throws AutomationException;

    void executePost(Map<String, Object> env, Object... params) throws AutomationException;

    String getName();

    String getParamType00();

    String getParamSrc00();

    String getParamDesc00();

    String getParamType01();

    String getParamSrc01();

    String getParamDesc01();

    String getParamType02();

    String getParamSrc02();

    String getParamDesc02();

    List<EnumEvents> getValidEventsAtPre();

    List<EnumEvents> getValidEventsAtPost();
}

The new class must be loaded into the package com.openkm.plugin.automation.action because the application plugin system will try to load it from there.

Do not omit the tag @PluginImplementation; otherwise, the application plugin system will not be able to retrieve the new class.

More information about registering a new plugin.

Methods description

MethodTypeDescription

executePre(Map<String, Object> env, Object... params)

void

The method executed by the Automation event when the validation conditions succeed, during the "pre" stage.

executePost(Map<String, Object> env, Object... params)

void

The method executed by the Automation event when the validation conditions succeed, during the "post" stage.

getName()

String

Sets the name that will be shown in the administrator user interface selector list.

getParamType00

getParamType01

getParamType02

String

Sets the parameter type.

Available values:

  • Automation.PARAM_TYPE_EMPTY
  • Automation.PARAM_TYPE_TEXT
  • Automation.PARAM_TYPE_INTEGER
  • Automation.PARAM_TYPE_BOOLEAN
  • Automation.PARAM_TYPE_TEXTAREA
  • Automation.PARAM_TYPE_CODE
  • Automation.PARAM_TYPE_USER
  • Automation.PARAM_TYPE_ROLE
  • Automation.PARAM_TYPE_OMR

When the value is set to Automation.PARAM_TYPE_EMPTY

The parameters work as a logical group.

[ getParamType00 + getParamSrc00 + getParamDesc00 ]

getParamSrc00

getParamSrc01

getParamSrc02

String

Sets the source type.

Available values:

  • Automation.PARAM_SOURCE_EMPTY
  • Automation.PARAM_SOURCE_FOLDER
  • Automation.PARAM_SOURCE_OMR

getParamDesc00

getParamDesc01

getParamDesc02

String

The parameter description.

getValidEventsAtPre()

List<EnumEvents>

Returns a list of events.

The method returns a list of valid events for the action in the pre stage.

getValidEventsAtPost()

List<EnumEvents>

Returns a list of events.

The method returns a list of valid events for the action in the post stage.

Understanding env variable

The env variable is present in the isValid method; it is a Map of values injected by automation. These map values provide information about the node involved in the event and other related information.

It takes some time to get familiar with the AutomationUtils class because the methods to retrieve data are centralized.

Take a look at Variables by automation event to see which variables are available for each event.

 For example, to retrieve the node that caused the event.

NodeBase node = automationUtils.getNodeToEvaluate(env);

Understanding params variable

The params variable is present in the isValid method; it is an array of Objects. This array is filled by the Automation event based on the number of parameters set on the Action class (which will not be the Automation.PARAM_TYPE_EMPTY value).

The array can have several Objects of distinct types; it is necessary to retrieve the parameters as the correct object types.

It takes some time to get familiar with the AutomationUtils class because the methods to retrieve parameters are centralized.

For example, to retrieve the first parameter as a String object.

String param00 = AutomationUtils.getString(0, params);

Description of available ParamType values:

PropertyDescription

Automation.PARAM_TYPE_EMPTY

Indicates an empty value.

Automation.PARAM_TYPE_TEXT

Indicates a text value will be required.

Automation.PARAM_TYPE_INTEGER

Indicates an integer value will be required.

Automation.PARAM_TYPE_BOOLEAN

Indicates a boolean value will be required.

Automation.PARAM_TYPE_TEXTAREA

Indicates a text area value will be required.

Automation.PARAM_TYPE_CODE

Indicates that code will be required.

Automation.PARAM_TYPE_USER

Indicates that a valid application user will be required.

Automation.PARAM_TYPE_ROLE

Indicates that a valid application role will be required.

Automation.PARAM_TYPE_OMR

Indicates that a valid OMR id - object mark recognition - will be required.

Description of available Src values:

PropertyDescription

PARAM_SOURCE_EMPTY

Indicates an empty source.

PARAM_SOURCE_FOLDER

Indicates that the source must be a folder.

PARAM_SOURCE_OMR

Indicates that the source must be a valid OMR - object mark recognition -.

Detecting recursion

When you create your automation actions, you should consider recursion. For example, if your action is linked to the "CREATE_DOCUMENT" event and the action creates a new document, you can enter an infinite loop. For this reason, when you create a new Action you should take special care with these cases.

Basic recursive samples:

  • Automation task linked with "Create document" event when an action that also creates a new document is set.
  • Automation task linked with "Set metadata group" event when an action that also changes metadata group values is set.

Complex recursive sample:

  • Automation task linked with "Create document" event when an action that changes metadata group values is set, and an automation task linked with "Set metadata group" event when an action that creates a new document is set.

Code to detect recursive calls caused by automation action classes:

if (StackTraceUtils.isCallingMe(this.getClass().getName())) {
  log.info("Recursion detected");
  return;
} 

Example

AddKeyword class:

package com.openkm.plugin.automation.action;

import com.openkm.core.Config;
import com.openkm.db.bean.Automation;
import com.openkm.db.bean.AutomationRule.EnumEvents;
import com.openkm.db.service.NodeBaseSrv;
import com.openkm.plugin.BasePlugin;
import com.openkm.plugin.automation.Action;
import com.openkm.plugin.automation.AutomationException;
import com.openkm.plugin.automation.AutomationUtils;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * AddKeyword
 */
@PluginImplementation
public class AddKeyword extends BasePlugin implements Action {

    private static ArrayList<EnumEvents> EVENTS_AT_PRE = new ArrayList<>();

    private static ArrayList<EnumEvents> EVENTS_AT_POST
            = Stream.of(EnumEvents.EVENT_DOCUMENT_CREATE, EnumEvents.EVENT_DOCUMENT_UPDATE, EnumEvents.EVENT_DOCUMENT_DELETE,
                    EnumEvents.EVENT_DOCUMENT_RENAME, EnumEvents.EVENT_DOCUMENT_MOVE, EnumEvents.EVENT_DOCUMENT_RESTORE_VERSION,
                    EnumEvents.EVENT_DOCUMENT_DOWNLOAD_FROM_UI, EnumEvents.EVENT_DOCUMENT_DOWNLOAD_FROM_UI_FOR_PREVIEW,
                    EnumEvents.EVENT_DOCUMENT_PRINT, EnumEvents.EVENT_DOCUMENT_STAMP, EnumEvents.EVENT_RECORD_CREATE,
                    EnumEvents.EVENT_RECORD_DELETE, EnumEvents.EVENT_FOLDER_CREATE, EnumEvents.EVENT_FOLDER_DELETE,
                    EnumEvents.EVENT_MAIL_CREATE, EnumEvents.EVENT_MAIL_DOWNLOAD_FROM_UI, EnumEvents.EVENT_LINK_CREATE,
                    EnumEvents.EVENT_TEXT_EXTRACTOR, EnumEvents.EVENT_PROPERTY_GROUP_ADD, EnumEvents.EVENT_PROPERTY_GROUP_SET,
                    EnumEvents.EVENT_PROPERTY_GROUP_REMOVE, EnumEvents.EVENT_MAIL_IMPORT_ATTACHMENTS
            ).collect(Collectors.toCollection(ArrayList::new));

    @Autowired
    private NodeBaseSrv nodeBaseSrv;

    @Autowired
    private AutomationUtils automationUtils;

    @Override
    public void executePre(Map<String, Object> env, Object... params) throws AutomationException {
    }

    @Override
    public void executePost(Map<String, Object> env, Object... params) throws AutomationException {
        try {
            String keyword = automationUtils.getString(0, params);
            String uuid = automationUtils.getNodeToEvaluate(env).getUuid();

            if (uuid != null && keyword != null && !keyword.isEmpty()) {
                if (Config.SYSTEM_KEYWORD_LOWERCASE) {
                    keyword = keyword.toLowerCase();
                }

                nodeBaseSrv.addKeyword(uuid, keyword);
            }
        } catch (Exception e) {
            throw new AutomationException("AddKeyword exception", e);
        }
    }

    @Override
    public String getName() {
        return "AddKeyword";
    }

    @Override
    public String getParamType00() {
        return Automation.PARAM_TYPE_TEXT;
    }

    @Override
    public String getParamSrc00() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc00() {
        return "Keyword";
    }

    @Override
    public String getParamType01() {
        return Automation.PARAM_TYPE_EMPTY;
    }

    @Override
    public String getParamSrc01() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc01() {
        return "";
    }

    @Override
    public String getParamType02() {
        return Automation.PARAM_TYPE_EMPTY;
    }

    @Override
    public String getParamSrc02() {
        return Automation.PARAM_SOURCE_EMPTY;
    }

    @Override
    public String getParamDesc02() {
        return "";
    }

    @Override
    public List<EnumEvents> getValidEventsAtPre() {
        return EVENTS_AT_PRE;
    }

    @Override
    public List<EnumEvents> getValidEventsAtPost() {
        return EVENTS_AT_POST;
    }
}