    /**
     * This executor can be used to start simple tasks.
     *
     * That an action can be executed it has to define a type. Supported types are:
     *
     * - workflows: `type="WORKFLOW"` (starts a workflow)
     * - technical workflows: `type="TECHNICAL_WORKFLOW"` (starts a workflow and deletes it after execution if the workflow is already finished, i.e. does not contain any user nodes)
     * - reminder: `type="REMINDER"` (creates a reminder)
     * - function modules: `type="FUNCTION"` (executes a function with the objId of the current object as only parameter)
     *
     * # Enhancement
     * An analyzer can enhance a context object with additional information.
     * Some properties in the action definition can use those information to dynamically change the configuration property.
     *
     * The following action properties can use those enhancement:
     *
     * - WORKFLOW / TECHNICAL_WORKFLOW : user
     * - WORKFLOW / TECHNICAL_WORKFLOW : templateId
     * - WORKFLOW / TECHNICAL_WORKFLOW : nameTemplate
     * - REMINDER : user
     * - REMINDER : nameTemplate
     *
     * # Configuration
     * Depending on the type, the action needs additional information:
     *
     *     {
     *       type: "WORKFLOW",
     *       user: "Administrator", // optional, if none is defined, the during initialization set user will be user
     *       templateId: "NameOrIdOfTheWorkflowTemplate",
     *       nameTemplate: "{{translate 'wfPrefix'}}: {{sord.name}}" // optional, default is the name of the sord
     *     }
     *
     *     {
     *       type: "TECHNICAL_WORKFLOW",
     *       user: "Administrator", // optional, if none is defined, the during initialization set user will be user
     *       templateId: "{{ctx.TemplateNameReadFromFieldByValueAnalyzer}}", // enhancement example
     *       nameTemplate: "{{translate 'wfPrefix'}}: {{sord.name}}" // optional, default is the name of the sord
     *     }
     *
     *     {
     *       type: "REMINDER",
     *       user: "Administrator", // optional, if none is defined, the during initialization set user will be user
     *       nameTemplate: "Erinnerung: {{sord.objKeys.CONTRACT_NAME}}" // optional, default is the name of the sord
     *     }
     *
     *     {
     *       type: "FUNCTION",                        // only one of `module`, `direct` or `regfct` will be used, priority order is `regfct` -> `direct` -> `module`
     *       module: "my.namespace.MyFunctionModule"  // tries to create a module with this name and calls its `process` function (module and its dependencies have to be included)
     *       direct: "my.direct.Rule"                 // calls a direct function with this name
     *       regfct: "RF_my_Function"                 // calls a registered function with this name
     *     }
     *
     * # Initialization example:
     *
     *     var executor = sol.create("sol.common_monitoring.as.executors.SimpleExecutor", {
     *       user: "Administrator" // The default user if an action specifies none
     *     });
     *
     * @author PZ, ELO Digital Office GmbH
     * @version 1.01.000
     *
     * @eloas
     *
     * @requires sol.common.IxUtils
     * @requires sol.common.ObjectUtils
     * @requires sol.common.SordUtils
     * @requires sol.common.DateUtils
     * @requires sol.common.WfUtils
     * @requires sol.common.ObjectFormatter
     * @requires sol.common.TranslateTerms
     * @requires sol.common.Template
     */
    sol.define("sol.common_monitoring.as.executors.SimpleExecutor", {

      /**
       * @cfg {String} user (optional) If set, this user will be used for all actions (but will be overridden, if an action itself defines a user)
       */

      /**
       * @private
       * @property {String} _todayIso The current date cached as ISO string
       */

      /**
       * @private
       * @property {Object} _userConnectionCache Caches user specific connections
       */
      _userConnectionCache: {},

      initialize: function (config) {
        var me = this;
        me.$super("sol.Base", "initialize", [config]);
        me._todayIso = sol.common.DateUtils.dateToIso(new Date());
        me.getConnection(me.user); // initializes a user connection in the cache for later re-use (if there is a user configured)
      },

      /**
       * Evaluates a result set and executes actions if the results contain any.
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object[]} results
       * @param {Object} ctx
       */
      execute: function (sord, results, ctx) {
        var me = this;

        me.logger.enter("execute", { objId: sord.id, name: String(sord.name) });

        if (results && (results.length > 0)) {
          results.forEach(function (r) {
            if (r.action) {
              me.executeAction(sord, r.action, ctx);
            }
          });
        }

        me.logger.exit("execute");
      },

      /**
       * Performes cleanup. Closes all opened user connections.
       */
      dispose: function () {
        var me = this;

        Object.keys(me._userConnectionCache || {})
          .map(me.getValueAtKey.bind(me, me._userConnectionCache))
          .map(me.disposeUserConnection);
      },

      /**
       * @private
       * get value at key
       * @param {Object} source
       * @param {String} key
       * @returns {Object} the object at provided key
       */
      getValueAtKey: function (source, key) {
        return source[key];
      },

      /**
       * @private
       * Closes an user cconnection
       * @param {de.elo.ix.client.IXConnection} userConnection
       */
      disposeUserConnection: function (userConnection) {
        userConnection.close();
      },

      /**
       * @private
       * Executes an individual action.
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} action
       * @param {Object} ctx
       */
      executeAction: function (sord, action, ctx) {
        var me = this,
            fct = me.ACTIONS[action.type];

        me.logger.debug("execute action", action);

        if (fct && sol.common.ObjectUtils.isFunction(fct)) {
          fct.call(me, sord, action, ctx);
        } else {
          throw "ActionExecutionFailed: unsupported action type: " + action.type;
        }
      },

      /**
       * @private
       * Retrieves a connection for a specific user, using an internal cache.
       * If no user is defined, it returns the standard connection.
       * @param {String} user
       * @return {de.elo.ix.client.IXConnection}
       */
      getConnection: function (user) {
        var me = this;

        if (!user) {
          return ixConnect;
        }
        if (!me._userConnectionCache[user]) {
          me._userConnectionCache[user] = ixConnect.createConnectionForUser(user);
        }
        return me._userConnectionCache[user];
      },

      /**
       * @private
       * Builds the name from a template using the sord data. Fallback is `sord.name`.
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} ctx
       * @param {String} nameTemplate (optional)
       * @return {String}
       */
      buildName: function (sord, ctx, nameTemplate) {
        var me = this,
            name;
        try {
          if (nameTemplate) {
            sord = sol.common.SordUtils.getTemplateSord(sord).sord;
            name = sol.create("sol.common.Template", { source: nameTemplate }).apply({ sord: sord, ctx: ctx });
          } else {
            name = sord.name;
          }
        } catch (ex) {
          name = sord.name;
          me.logger.warn("error generating name, use 'sord.name'", ex);
        }
        return name;
      },

      /**
       * @private
       * Retrieves the value from a action using handlebars applying the sord and the context.
       * @param {String} value
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} ctx
       * @return {String}
       */
      eveluateActionProperty: function (value, sord, ctx) {
        var me = this,
            result = value;
        if (value.indexOf("{{") > -1) {
          try {
            sord = sol.common.SordUtils.getTemplateSord(sord).sord;
            result = sol.create("sol.common.Template", { source: value }).apply({ sord: sord, ctx: ctx });
          } catch (ignore) {
            me.logger.debug("error evaluating handlebars action property", ignore);
          }
        }
        return result;
      },

      /**
       * @private
       * @property
       * Lookup object for the different functions supported by this executor.
       * All functions will be called with a `de.elo.ix.client.Sord` as first, an object (representing the action which should be executed) as second parameter and an context object possibly containing additional informations.
       */
      ACTIONS: {
        WORKFLOW: function (sord, action, ctx) {
          var me = this,
              flowTemplate, flowName, flowUser, conn, flowId;

          flowName = me.buildName(sord, ctx, action.nameTemplate);
          flowTemplate = me.eveluateActionProperty(action.templateId, sord, ctx);
          flowUser = (action.user) ? me.eveluateActionProperty(action.user, sord, ctx) : me.user;
          conn = me.getConnection(flowUser);
          flowId = conn.ix().startWorkFlow(flowTemplate, flowName, sord.id);
          me.logger.info(["workflow started: flowId={0}, flowName={1}, flowOwner={2}", flowId, flowName, flowUser]);
        },
        TECHNICAL_WORKFLOW: function (sord, action, ctx) {
          var me = this,
              flowTemplate, flowName, flowUser, conn, flowId, activeWorkflows, flowFinished;

          flowName = me.buildName(sord, ctx, action.nameTemplate);
          flowTemplate = me.eveluateActionProperty(action.templateId, sord, ctx);
          flowUser = (action.user) ? me.eveluateActionProperty(action.user, sord, ctx) : me.user;
          conn = me.getConnection(flowUser);
          flowId = conn.ix().startWorkFlow(flowTemplate, flowName, sord.id);
          me.logger.info(["workflow started: flowId={0}, flowName={1}, flowOwner={2}", flowId, flowName, flowUser]);

          activeWorkflows = sol.common.WfUtils.getActiveWorkflows(sord.id, { template: flowTemplate });
          flowFinished = !activeWorkflows.some(function (wf) {
            return wf.id === flowId;
          });
          if (flowFinished) {
            me.logger.info(["delete finished workflow: flowId={0}, flowName={1}, flowOwner={2}", flowId, flowName, flowUser]);
            me.getConnection(flowUser).ix().deleteWorkFlow(flowId, WFTypeC.FINISHED, LockC.NO);
          }

        },
        REMINDER: function (sord, action, ctx) {
          var me = this,
              user, reminder;

          user = (action.user) ? me.eveluateActionProperty(action.user, sord, ctx) : me.user;

          if (user) {
            reminder = ixConnect.ix().createReminder(sord.id);
            reminder.name = me.buildName(sord, ctx, action.nameTemplate);
            reminder.promptDateIso = me._todayIso;
            //reminder.prio = UserTaskPriorityC.HIGHEST;
            //reminder.desc = "...";
            ixConnect.ix().checkinReminder(reminder, [user], false, LockC.NO);
            me.logger.info(["reminder created: objId={0}, user={1}", sord.id, user]);
          }
        },
        FUNCTION: function (sord, action, ctx) {
          // TODO: can this result in a new "nextRun"?  --> see e.g. File
          var me = this,
              paramObj = { objId: sord.id };
          if (action.regfct) {
            sol.common.IxUtils.execute(action.regfct, paramObj);
            me.logger.info(["refistered function executed: {0}", action.regfct]);
            return;
          }
          if (action.direct) {
            if (ruleExecutor.hasDirectRule(action.direct)) {
              ruleExecutor.runDirectRule(action.direct, sord.id, JSON.stringify(paramObj), "");
            } else {
              me.logger.debug(["Direct rule '{0}' not found.", action.direct]);
            }
            return;
          }
          if (action.module) {
            sol.create(action.module, paramObj).process();
            me.logger.info(["function module executed: {0}", action.module]);
          }
        }
      }

    });