    //@include lib_Class.js
    //@include lib_sol.common.ObjectFormatter.js
    //@include lib_sol.common.Config.js
    //@include lib_sol.common.Template.js
    //@include lib_sol.common.WfUtils.js
    //@include lib_sol.common.ix.RfUtils.js
    //@include lib_sol.common.ix.ServiceRegistry.js

    var logger = sol.create("sol.Logger", { scope: "sol.common_monitoring.ix.events.Update" });

    globalScope.$monitoring = globalScope.$monitoring || {};
    globalScope.$monitoring.updateRegistry = globalScope.$monitoring.updateRegistry || {};
    globalScope.$monitoring.updateRegistryWF = globalScope.$monitoring.updateRegistryWF || {};

    /**
     * Event class for registering or executing an update.
     *
     * @author PZ, ELO Digital Office GmbH
     * @version 1.05.000
     *
     * @eloix
     * @requires sol.common.ObjectFormatter
     * @requires sol.common.Template
     * @requires sol.common.WfUtils
     * @requires sol.common.ix.RfUtils
     * @requires sol.common.ix.ServiceRegistry
     */
    sol.define("sol.common_monitoring.ix.events.Update", {

      /**
       * Executes the update if one is registered for the element.
       */
      process: function () {
        var me = this,
            update;

        if (!me.sord) {
          throw "IllegalConfigurationException: no 'sord' defined.";
        }

        me.guid = me.sord.guid;

        if (!me.sordZ.isTrue(SordC.mbObjKeys)) {
          me.sordZ.add(SordC.mbObjKeys);
          me.sord = ixConnect.ix().checkoutSord(me.sord.id, me.sordZ, LockC.NO);
        }

        update = me.getUpdateCfg();

        if (update) {
          me.wfTemplate = update.templateId;
          me.wfUser = update.user;
          me.wfName = me.buildName(me.sord, update.nameTemplate);

          me.flowId = me.getConnection().ix().startWorkFlow(me.wfTemplate, me.wfName, me.guid);
          me.logger.debug(["workflow started: flowId={0}, flowName={1}, flowOwner={2}, objId={3}", me.flowId, me.wfName, me.wfUser, me.sord.id]);

          me.cleanUp();
        }
      },

      /**
       * Registers an update for an element by retrieving the configuration from the service registry.
       */
      register: function () {
        var me = this,
            sord, guid;

        if (!me.objId) {
          throw "IllegalConfigurationException: no 'objId' defined.";
        }

        sord = ixConnect.ix().checkoutSord(me.objId, SordC.mbMin, LockC.NO);
        guid = sord.guid;

        if ((me.registerFlowId > 0) && (me.registerNodeId > 0)) {
          me.getUpdateRegistryWF()[me.registerFlowId] = me.registerNodeId;
        } else {
          me.getUpdateRegistry()[guid] = true;
        }
      },

      /**
       * @private
       * Retrieves a connection for the specified user.
       * If no user is defined, it returns the standard connection.
       * @return {de.elo.ix.client.IXConnection}
       */
      getConnection: function () {
        var me = this;
        if (!me.wfUser || (me.wfUser == me.user)) {
          return ixConnect;
        }
        if (!me._internalConnection) {
          me._internalConnection = ixConnect.createConnectionForUser(me.wfUser);
        }
        return me._internalConnection;
      },

      /**
       * @private
       * Performs internal cleanup.
       */
      cleanUp: function () {
        var me = this;

        me.removeFinishedWf();

        if (me._internalConnection) {
          me._internalConnection.close();
        }
      },

      /**
       * @private
       * Retrieves an update configuration for an element.
       * @return {Object}
       */
      getUpdateCfg: function () {
        var me = this,
            solType, updateCfgs;

        solType = sol.common.SordUtils.getObjKeyValue(me.sord, "SOL_TYPE");

        updateCfgs = sol.common.ix.ServiceRegistry.query({
          type: sol.common.ix.ServiceRegistry.TYPES.CONFIG,
          functions: sol.common.ix.ServiceRegistry.FUNCTIONS.REGISTER_UPDATE,
          soltypes: String(solType)
        }, {
          evaluateConfig: true
        });

        return (updateCfgs && (updateCfgs.length > 0)) ? updateCfgs[0].serviceDescription.cfg : null;
      },

      getUpdateRegistry: function () {
        return globalScope.$monitoring.updateRegistry;
      },

      getUpdateRegistryWF: function () {
        return globalScope.$monitoring.updateRegistryWF;
      },

      /**
       * @private
       * Remove the update WF if it is already finished.
       */
      removeFinishedWf: function () {
        var me = this,
            activeWorkflows, flowFinished;

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

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

      /**
       * @private
       * Creates a template sord from a Sord (see {@link sol.common.ObjectFormatter.TemplateSord TemplateSord}).
       * @param {de.elo.ix.client.Sord} sord
       * @return {Object}
       */
      getTemplateSord: function (sord) {
        var templateSord;

        templateSord = sol.common.ObjectFormatter.format({
          sord: {
            formatter: "sol.common.ObjectFormatter.TemplateSord",
            data: sord,
            config: {
              sordKeys: ["id", "guid", "maskName", "name", "desc", "IDateIso", "XDateIso", "ownerName"],
              allMapFields: true
            }
          }
        });
        return templateSord;
      }

    });

    /**
     * This asynchronous event is raised after a Sord object has been written and executes an update if one is registered for the element.
     * @static
     * @member sol.common_monitoring.ix.events.Update
     * @method onAfterCheckinSord
     * @param {de.elo.ix.client.IXServerEventsContext} ec
     * @param {de.elo.ix.client.Sord} sord
     * @param {de.elo.ix.client.Sord} sordCurrent
     * @param {de.elo.ix.client.Sord} sordParent
     * @param {de.elo.ix.client.LockZ} sordZ
     * @param {de.elo.ix.client.SordZ} lockZ
     * @throws RemoteException Exception thrown by the script itself or scripting engine.
     */
    function onAfterCheckinSord(ec, sord, sordCurrent, sordParent, sordZ, lockZ) {
      var event;

      if (!globalScope.$monitoring || !globalScope.$monitoring.updateRegistry || (globalScope.$monitoring.updateRegistry[sord.guid] !== true) || (sordZ == 0)) {
        return;
      }

      // Cleanup as first step to aviod concurrent access from competing events
      delete globalScope.$monitoring.updateRegistry[sord.guid];

      logger.enter("onAfterCheckinSord_ExecuteUpdate");
      try {
        event = sol.create("sol.common_monitoring.ix.events.Update", {
          sord: sord,
          sordZ: sordZ,
          user: ec.user.name
        });
        event.process();
      } catch (ex) {
        logger.error("Exception in 'onAfterCheckinSord_ExecuteUpdate'", ex);
      }
      logger.exit("onAfterCheckinSord_ExecuteUpdate");
    }

    /**
     * This asynchronous event is raised after a workflow has been forwarded and executes an update if one is registered for the workflow.
     * @static
     * @member sol.common_monitoring.ix.events.Update
     * @method onAfterEndEditWorkFlowNode
     * @param {de.elo.ix.client.IXServerEventsContext} ec
     * @param {de.elo.ix.client.WFDiagram} wfDiagram
     * @param {Number} nodeId
     * @param {de.elo.ix.client.Sord} sord
     * @param {de.elo.ix.client.LockZ} sordZ
     * @throws RemoteException Exception thrown by the script itself or scripting engine.
     */
    function onAfterEndEditWorkFlowNode(ec, wfDiagram, nodeId, sord, sordZ) {
      var event;

      if (!globalScope.$monitoring || !globalScope.$monitoring.updateRegistryWF || (globalScope.$monitoring.updateRegistryWF[wfDiagram.id] != nodeId)) {
        return;
      }

      // Cleanup as first step to aviod concurrent access from competing events
      delete globalScope.$monitoring.updateRegistryWF[wfDiagram.id];

      logger.enter("onAfterEndEditWorkFlowNode_ExecuteUpdate");

      try {
        event = sol.create("sol.common_monitoring.ix.events.Update", {
          sord: sord,
          sordZ: sordZ,
          registerFlowId: wfDiagram.id,
          registerNodeId: nodeId,
          user: ec.user.name
        });
        event.process();
      } catch (ex) {
        logger.error("Exception in 'onAfterCheckinSord_ExecuteUpdate'", ex);
      }

      logger.exit("onAfterEndEditWorkFlowNode_ExecuteUpdate");
    }

    /**
     * Registers an update event.
     * @member sol.common_monitoring.ix.events.Update
     * @method RF_sol_common_monitoring_function_RegisterUpdate
     * @static
     * @inheritdoc sol.common.ix.FunctionBase#RF_FunctionName
     */
    function RF_sol_common_monitoring_function_RegisterUpdate(ec, args) {
      var params, module;

      logger.enter("RF_sol_common_monitoring_function_RegisterUpdate", args);

      params = sol.common.ix.RfUtils.parseAndCheckParams(ec, arguments.callee.name, args, "objId");

      module = sol.create("sol.common_monitoring.ix.events.Update", params);
      module.register();

      logger.exit("RF_sol_common_monitoring_function_RegisterUpdate");

      return "{}";
    }