    importPackage(Packages.de.elo.ix.client);

    //@include lib_Class.js
    //@include lib_sol.common.Cache.js
    //@include lib_sol.common.StringUtils.js
    //@include lib_sol.common.AclUtils.js
    //@include lib_sol.common.JsonUtils.js
    //@include lib_sol.common.ObjectFormatter.js

    /**
     * Local definition of the class `sol.common.Cache` for backward compatibility of previous solution packages.
     */
    if (!sol.ClassManager.getClass("sol.common.Cache")) {
      sol.define("sol.common.Cache", {

        initialize: function (config) {
          var me = this;
          me.cache = new java.util.concurrent.ConcurrentHashMap(8, 0.9, 1);
        },

        /**
         * Inserts the specified key-value pair into the cache.
         * @param {String} key
         * @param {Object} value
         * @return {Object} The previous value associated with the key, or null if there was no mapping before
         */
        put: function (key, value) {
          var me = this;
          return me.cache.put(key, value);
        },

        /**
         * Inserts all key-value pairs specified by an object into the cache. Existing mappings will be replaced.
         * @param {Object} data Property names will be used as keys and the associated values as values.
         */
        putAll: function (data) {
          var me = this;
          me.cache.putAll(data);
        },

        /**
         * Tests if the specified object is a key in the cache.
         * @param {String} key
         * @return {Boolean}
         */
        containsKey: function (key) {
          var me = this;
          return me.cache.containsKey(key);
        },

        /**
         * Returns the value for the specified key from the cache, or null if the chache contains no mapping for the key.
         * @param {String} key
         * @return {Object}
         */
        get: function (key) {
          var me = this;
          return me.cache.get(key);
        },

        /**
         * Returns an enumeration of all keys in the cache.
         * @return {Object} An `java.util.Enumeration` of all keys
         */
        keys: function () {
          var me = this;
          return me.cache.keys();
        },

        /**
         * Returns a collection view of the values contained in the cache.
         * @return {Object} An `java.util.Collection` of all values
         */
        values: function () {
          var me = this;
          return me.cache.values();
        },

        /**
         * Returns an enumeration of the values in the cache.
         * @return {Object} An `java.util.Enumeration` of all values
         */
        elements: function () {
          var me = this;
          return me.cache.elements();
        },

        /**
         * Removes the key (and its corresponding value) from the cache.
         * @param {String} key
         * @return {Object} The previous value associated with the key, or null if there was no value for the key
         */
        remove: function (key) {
          var me = this;
          return me.cache.remove(key);
        },

        /**
         * Returns the number of key-value pairs in the cache.
         * @return {Number}
         */
        size: function () {
          var me = this;
          return me.cache.size();
        },

        /**
         * Returns `true` if the chache contains no key-value pairs.
         * @return {Boolean}
         */
        isEmpty: function () {
          var me = this;
          return me.cache.isEmpty();
        },

        /**
         * Removes all of the mappings from the cache.
         */
        clear: function () {
          var me = this;
          me.cache.clear();
        }
      });
    }

    /**
     * This class contains convenience methods for working with Sord objects in server scripts.
     *
     * @author PZ, ELO Digital Office GmbH
     * @version 1.03.000
     *
     * @eloix
     * @eloas
     * @elojc
     *
     * @requires sol.common.Cache
     * @requires sol.common.StringUtils
     * @requires sol.common.ObjectFormatter
     */
    sol.define("sol.common.SordUtils", {
      singleton: true,
      requires: ["sol.common.Cache"],

      pilcrow: "\u00b6",

      /**
       * @private
       * @property {sol.common.Cache} docMaskCache Cache for `de.elo.ix.client.DocMask`
       */

      initialize: function (config) {
        var me = this;
        me.$super("sol.Base", "initialize", [config]);
        me.docMaskCache = sol.create("sol.common.Cache");
      },

      /**
       * Checks, if an object is a de.elo.ix.client.Sord
       * @param {Object} sord
       * @return {Boolean}
       */
      isSord: function (sord) {
        return (sord instanceof Sord);
      },

      /**
       * Checks, if the index data (objKeys) is loaded
       * @param {de.elo.ix.client.Sord} sord
       * @return {Boolean}
       */
      isIndexdataLoaded: function (sord) {
        return sord && sord.objKeys && (sord.objKeys.length > 0);
      },

      /**
       * Checks, if a de.elo.ix.client.Sord is from type folder
       * @param {de.elo.ix.client.Sord} sord
       * @return {Boolean}
       */
      isFolder: function (sord) {
        return (sord.type < SordC.LBT_DOCUMENT);
      },

      /**
       * Checks, if a de.elo.ix.client.Sord is a dynamic folder.
       * @param {de.elo.ix.client.Sord} sord
       * @return {Boolean}
       */
      isDynamicFolder: function (sord) {
        var me = this,
            desc;
        if (!me.isFolder(sord)) {
          return false;
        }
        desc = sord.desc;
        return !sol.common.StringUtils.isBlank(desc) && (desc.matches("^![\+|\?|!].*"));
      },

      /**
       * Checks, if a de.elo.ix.client.Sord is from type document
       * @param {de.elo.ix.client.Sord} sord
       * @return {Boolean}
       */
      isDocument: function (sord) {
        return (sord.type >= SordC.LBT_DOCUMENT) && (sord.type <= SordC.LBT_DOCUMENT_MAX);
      },

      /**
       * Updates all of Sord attributes and ObjKeys.
       * Map Keys are not updated immediately, instead the function returns an Array with KeyValues, which can be checked in later.
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object[]} data
       *
       *     {
       *       key: "name",
       *       type: "GRP", // SORD|GRP|MAP
       *       value: "hallo welt"
       *     }
       *
       * @param {Object} params Parameters
       * @param {Boolean} params.silent Silent
       * @returns {de.elo.ix.client.KeyValue[]}
       */
      updateSord: function (sord, data, params) {
        var me = this,
            mapEntries, result, dataString, paramsString;

        params = params || {};

        me.logger.enter("updateSord");

        if (me.logger.debugEnabled) {
          dataString = sol.common.JsonUtils.stringifyAll(data);
          paramsString = sol.common.JsonUtils.stringifyAll(params);
          me.logger.debug(["updateSord: data={0}, params={1}", dataString, paramsString]);
        }

        mapEntries = [];
        if (!me.isSord(sord) || !data) {
          me.logger.exit("updateSord");
          return;
        }

        if (!Array.isArray(data)) {
          throw "data has to be an Array";
        }

        data.forEach(function (entry) {
          if (!entry || !entry.type || !entry.key || entry.value === undefined || entry.value === null) {
            throw "illegal object: " + JSON.stringify(data);
          }
          switch (entry.type) {
            case "SORD":
              sord[entry.key] = entry.value;
              break;
            case "GRP":
              me.setObjKeyValue(sord, entry.key, entry.value, params);
              break;
            case "MAP":
              mapEntries.push(new KeyValue(entry.key, entry.value));
              break;
            default:
              throw "unsupported type: " + entry.type;
          }
        });

        result = (mapEntries.length > 0) ? mapEntries : null;
        me.logger.exit("updateSord", "mapEntries.length=" + mapEntries.length);
        return result;
      },

      /**
       * Updates a bunch of index data at once.
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} indexData Key-value-pairs with key=field and value=new value
       */
      updateKeywording: function (sord, indexData) {
        var me = this,
            property;

        me.logger.enter("updateKeywording", arguments);
        for (property in indexData) {
          if (indexData.hasOwnProperty(property)) {
            this.setObjKeyValue(sord, property, indexData[property]);
          }
        }
        me.logger.exit("updateKeywording");
      },

      /**
       * Checks if an ObjKey exists
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName
       * @returns {Boolean}
       */
      objKeyExists: function (sord, keyName) {
        return this.getObjKey(sord, keyName) !== null;
      },

      /**
       * Retrieves values from a Sord.
       * This could be a Sord property, an objKey, a map field or a form blob field.
       *
       * This can retrieve lists from `ObjKeys` and multiple map values.
       *
       *     {
       *       key: "FIELD_NAME",
       *       type: "GRP", // SORD|GRP|MAP
       *     }
       *
       *     {
       *       key: "INDEXED_MAP_FIELD*",
       *       type: "MAP", // SORD|GRP|MAP
       *     }
       *
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} params Parameter
       * @param {String} params.key Key
       * @param {String} params.type Type
       * @param {Number} params.maxLength Max length
       * @param {Number} params.fillString Fill string, e.g. `00000000000000`
       * @return {String[]} Can be null
       */
      getValues: function (sord, params) {
        var me = this,
            values = null,
            tmpValues, i, fieldDefString, value;

        if (!sord) {
          throw "Sord is empty";
        }
        if (!params || !params.type || !(params.key || params.value)) {
          fieldDefString = JSON.stringify(params);
          throw "Field definition is incomplete: fieldDef=" + fieldDefString;
        }

        switch (params.type) {
          case "SORD":
            if (sord[params.key]) {
              values = [String(sord[params.key])];
            }
            break;
          case "GRP":
            tmpValues = me.getObjKeyValues(sord, params.key);
            if (tmpValues && (tmpValues.length > 0)) {
              values = tmpValues;
            }
            break;
          case "MAP":
            tmpValues = ixConnect.ix().checkoutMap(MapDomainC.DOMAIN_SORD, sord.id, [params.key], LockC.NO).items;
            if (tmpValues && (tmpValues.length > 0)) {
              values = [];
              for (i = 0; i < tmpValues.length; i++) {
                values.push(String(tmpValues[i].value));
              }
            }
            break;
          case "SORDBLOB":
            value = me.getStringMapBlob({ mapDomain: MapDomainC.DOMAIN_SORD, mapId: sord.id, key: params.key });
            if (value) {
              values = [value];
            }
            break;
          case "FORMBLOB":
            value = me.getStringMapBlob({ mapDomain: "FORMDATA", mapId: sord.id, key: params.key });
            if (value) {
              values = [value];
            }
            break;
          case "CONST":
            if (params.value) {
              values = [String(params.value)];
            }
            break;
          default:
            throw "unsupported type: " + params.type;
        }

        if (values && (values.length > 0)) {

          if (params.maxLength) {
            for (i = 0; i < values.length; i++) {
              value = values[i] + "";
              value = (value.length > params.maxLength) ? value.substr(0, params.maxLength) : value;
              values[i] = value;
            }
          }

          if (params.fillString) {
            for (i = 0; i < values.length; i++) {
              value = values[i] + "";
              if (value.length < params.fillString.length) {
                value += params.fillString.substr(value.length);
              }
              values[i] = value;
            }
          }
        }

        return values;
      },

      /**
       * Returns an object map blob
       * @param {Object} params Parameters
       * @param {String} [params.mapDomain=MapDomainC.DOMAIN_SORD] Map domain
       * @param {String} params.mapId Map ID
       * @param {String} params.key Map key
       * @return {Object}
       */
      getObjectMapBlob: function (params) {
        var me = this,
            obj, str;

        params = params || {};

        str = me.getStringMapBlob(params);

        obj = JSON.parse(str);

        return obj;
      },

      /**
       * Returns a string map blob
       * @param {Object} params Parameters
       * @param {String} [params.mapDomain=MapDomainC.DOMAIN_SORD] Map domain
       * @param {String} params.mapId Map ID
       * @param {String} params.key Map key
       */
      getStringMapBlob: function (params) {
        var me = this,
            mapEntries, mapEntry, dataString;

        params = params || {};

        if (!params.mapId) {
          throw "Map ID is missing";
        }

        if (!params.key) {
          throw "Key is missing";
        }

        params.mapDomain = params.mapDomain || MapDomainC.DOMAIN_SORD;

        mapEntries = ixConnect.ix().checkoutMap(params.mapDomain, params.mapId, [params.key], LockC.NO).items;

        if (!mapEntries || (mapEntries.length == 0)) {
          return;
        }

        mapEntry = mapEntries[0];

        dataString = me.getBlobDataFromMapEntry(mapEntry);

        return dataString;
      },

      /**
       * Sets an object map blob
       * @param {Object} params Parameters
       * @param {String} params.mapId Map ID
       * @param {String} params.key Key
       * @param {Object} params.value Value
       * @param {String} [params.mapDomain=MapDomainC.DOMAIN_SORD] Map domain
       * @param {String} params.objId Object ID
       */
      setObjectMapBlob: function (params) {
        var me = this;

        params = params || {};

        params.value = JSON.stringify(params.value, 2);

        me.setStringMapBlob(params);
      },

      /**
       * Sets a string map blob
       * @param {Object} params Parameters
       * @param {String} params.mapId Map ID
       * @param {String} params.key Key
       * @param {String} params.value Value
       * @param {String} [params.mapDomain=MapDomainC.DOMAIN_SORD] Map domain
       * @param {String} params.objId Object ID
       */
      setStringMapBlob: function (params) {
        var me = this,
            stringMapBlob;

        params = params || {};

        if (!params.mapId) {
          throw "Map ID is missing";
        }

        if (!params.key) {
          throw "Map key is missing";
        }

        params.mapDomain = params.mapDomain || MapDomainC.DOMAIN_SORD;
        stringMapBlob = me.createStringMapBlob(params.key, params.value);

        if (!params.objId && (params.mapDomain == MapDomainC.DOMAIN_SORD)) {
          params.objId = params.mapId;
        }

        if (!params.objId) {
          throw "Object ID is empty";
        }

        ixConnect.ix().checkinMap(params.mapDomain, params.mapId, params.objId, [stringMapBlob], LockC.NO);
      },

      /**
       * Creates a string map blob
       * @param {String} key Key
       * @param {String} value Value
       * @return {de.elo.ix.client.MapValue} Map blob
       */
      createStringMapBlob: function (key, value) {
        var str, bytes, fileData, stringMapBlob;

        if (!key) {
          throw "Key is empty";
        }

        value = value || "";

        str = new java.lang.String(value);
        bytes = str.getBytes("UTF-8");

        fileData = new FileData("text/plain", bytes);
        stringMapBlob = new MapValue(key, fileData);

        return stringMapBlob;
      },

      /**
       * Retrieves a value from a Sord.
       * This could be a Sord property, an objKey or a map field.
       *
       * If there are more than one value, first value will be returned.
       *
       * Uses {@link #getValues}.
       *
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} params Parameter
       * @param {String} params.key Key
       * @param {String} params.type Type
       * @param {Number} params.fillString Fill string, e.g. `00000000000000`
       * @param {Number} params.maxLength Max length
       *
       *     {
       *       key: "name",
       *       type: "GRP", // SORD|GRP|MAP|FORMBLOB
       *     }
       *
       * @return {String}
       */
      getValue: function (sord, params) {
        var me = this,
            value = null,
            values;

        values = me.getValues(sord, params);

        if (values && (values.length > 0)) {
          value = values[0];
        }

        return value;
      },

      /**
       * Returns the ObjKey for a field
       * @param {de.elo.ix.client.Sord} sord
       * @param {string} keyName Name of the index field
       * @return {de.elo.ix.client.ObjKey} The ObjKey, or null if none was found
       */
      getObjKey: function (sord, keyName) {
        var keys, key, i;
        if (this.isSord(sord) && this.isIndexdataLoaded(sord) && keyName) {
          keys = sord.objKeys;
          for (i = 0; i < keys.length; i++) {
            key = keys[i];
            if (key.name == keyName) {
              return key;
            }
          }
        }
        return null;
      },

      /**
       * Returns the value of an ObjKey for a field
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @return {String} The field value
       */
      getObjKeyValue: function (sord, keyName) {
        var values = this.getObjKeyValues(sord, keyName);
        if (values) {
          return values[0];
        }
        return null;
      },

      /**
       * Returns the value of an ObjKey for a field as number.
       * The method takes care of wrong decimal separators.
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @param {Object} params Parameters
       * @param {Boolean} [params.throwException=false] Throw exception
       * @return {Number} The field value as number
       */
      getObjKeyValueAsNumber: function (sord, keyName, params) {
        var me = this,
            rawValue, validNumberFormat, message, stringValue, number;

        params = params || {};

        rawValue = me.getObjKeyValue(sord, keyName);

        if (rawValue == null) {
          me.logger.debug(["getObjKeyValueAsNumber: No values exist: sord.id={0}, sord.name={1}, keyName={2}", sord.id, sord.name, keyName]);
          return null;
        }

        rawValue += "";

        validNumberFormat = me.isValidNumberFormat(rawValue);

        if (!validNumberFormat) {
          message = me.logger.format(["getObjKeyValueAsNumber: Invalid number format: sord.id={0}, sord.name={1}, keyName={2}, rawValue={3}", sord.id, sord.name, keyName, rawValue]);
          if (params.throwException) {
            throw message;
          } else {
            me.logger.warn(message);
          }
        }

        stringValue = rawValue.replace(",", ".");

        number = parseFloat(stringValue);

        me.logger.debug(["getObjKeyValueAsNumber: sord.id={0}, sord.name={1}, keyName={2}, rawValue={3}, number={5}", sord.id, sord.name, keyName, rawValue, stringValue, number]);

        return number;
      },

      /**
       * Checks wether the numberString is a valid number
       * @param {String} numberString Number string
       * @return {Boolean} True if the string contains a valid number
       */
      isValidNumberFormat: function (numberString) {
        var valid;

        numberString = (numberString || "") + "";

        valid = /^-*\d*[.,]{0,1}\d*$/.test(numberString);

        return valid;
      },

      /**
       * Sets the value of an ObjKey for a field as number.
       * The method takes care of the decimal separator.
       *
       * Be carefull if using not the users IX connection to checkin the sord after using this method.
       * This could cause problems with the separator. Use additional `params.language` parameter where language is the ISO country code of the connection used to checkin the sord afterwards.
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @param {String} value Value
       * @param {Object} params (optional)
       * @param {String} params.language (optional) ISO language code to determine the decimal separator
       * @param {Boolean} [params.throwException=false] Throw exception
       * @param {de.elo.ix.client.IXConnection} params.conn IX connection
       */
      setObjKeyValueAsNumber: function (sord, keyName, value, params) {
        var me = this,
            validNumberFormat, stringValue, message, normalizedValue;

        params = params || {};
        stringValue = value + "";

        validNumberFormat = me.isValidNumberFormat(stringValue);

        if (!validNumberFormat) {
          message = me.logger.format(["setObjKeyValueAsNumber: Invalid number format: sord.id={0}, sord.name={1}, keyName={2}, value={3}, params={4}", sord.id, sord.name, keyName, value, JSON.stringify(params)]);
          if (params.throwException) {
            throw message;
          } else {
            me.logger.warn(message);
          }
        }

        normalizedValue = me.normalizeNumber(value, params.lang, params.conn);

        me.logger.debug(["setObjKeyValueAsNumber: sord.id={0}, sord.name={1}, keyName={2}, stringValue={3}, normalizedValue={4}", sord.id, sord.name, keyName, stringValue, normalizedValue]);
        me.setObjKeyValue(sord, keyName, normalizedValue);
      },

      /**
       * Increments the value of an ObjKey
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @return {Number} The field value as number
       */
      incObjKeyValue: function (sord, keyName) {
        var me = this,
            value;

        value = me.getObjKeyValueAsNumber(sord, keyName);
        value++;
        me.setObjKeyValueAsNumber(sord, keyName, value);

        return value;
      },

      /**
       * Decrements the value of an ObjKey
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @return {Number} The field value as number
       */
      decObjKeyValue: function (sord, keyName) {
        var me = this,
            value;

        value = me.getObjKeyValueAsNumber(sord, keyName);
        value--;
        if (value == 0) {
          me.setObjKeyValue(sord, keyName, value);
        } else {
          me.setObjKeyValueAsNumber(sord, keyName, value);
        }
        return value;
      },

      /**
       * Adjusts the decimal separator of a number
       * @param {String} value Value
       * @param {String} language ISO country code to determine the decimal separator
       * @param {de.elo.ix.client.IXConnection} conn IX connection
       * @return {String} normalized Number
       */
      normalizeNumber: function (value, language, conn) {
        var me = this,
            stringValue, groups, decimalSeparator, normalizedValue;

        stringValue = (value || "") + "";

        stringValue = stringValue.trim();

        groups = stringValue.match(/(^-?\d+)[\.|,](\d+$)/);

        decimalSeparator = (language) ? me.getDecimalSeparatorForLanguage(language) : me.getDecimalSeparatorForIx(conn);

        if (groups && (groups.length == 3)) {
          normalizedValue = groups[1] + decimalSeparator + groups[2];
        } else {
          normalizedValue = stringValue;
        }

        me.logger.debug(["normalizeNumber: value={0}, normalizedValue={1}", stringValue, normalizedValue]);

        return normalizedValue;
      },

      /**
       * Returns the decimal separator for the ELO index server
       * @param {de.elo.ix.client.IXConnection} conn IX connection
       * @returns {String}
       */
      getDecimalSeparatorForIx: function (conn) {
        var me = this,
            language, country, decimalSeparator, connectionUserName;

        conn = conn || ixConnect;

        language = conn.loginResult.clientInfo.language;
        country = conn.loginResult.clientInfo.country;

        decimalSeparator = me.getDecimalSeparatorForLanguage(language, country);

        connectionUserName = conn.loginResult.user.name;

        me.logger.debug(["getDecimalSeparatorForIX: connectionUserName={0}, language={1}, country={2}, decimalSeparator={3}", connectionUserName, language || "", country || "", decimalSeparator]);

        return decimalSeparator;
      },

      /**
       * Returns the decimal separator for a language
       * @param {String} language ISO language code to determine the decimal separator
       * @param {String} country ISO country code to determine the decimal separator
       * @returns {String}
       */
      getDecimalSeparatorForLanguage: function (language, country) {
        var decimalSeparatorChar, decimalSeparator;

        decimalSeparatorChar = new java.text.DecimalFormatSymbols(new java.util.Locale(language, country)).decimalSeparator;
        decimalSeparator = String(java.lang.Character.toString(decimalSeparatorChar));

        return decimalSeparator;
      },

      /**
       * Returns the values of an ObjKey for a field as array
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @return {String[]} The field values
       */
      getObjKeyValues: function (sord, keyName) {
        var me = this,
            key, values, i, value;

        key = me.getObjKey(sord, keyName);

        if (key && key.data) {
          for (i = 0; i < key.data.length; i++) {
            value = key.data[i];
            if (typeof value != "undefined") {
              values = values || [];
              values.push(String(value));
            }
          }
        }

        return values;
      },

      /**
       *
       * Sets the value of an ObjKey for a field
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @param {String|String[]} value could be a multi index string (e.g. a¶b¶c). In this case the value will convert to an array before each item is set
       * @param {Object} params Parameters
       * @param {Boolean} params.silent Silent
       * @return {de.elo.ix.client.ObjKey} The changed ObjKey
       */
      setObjKeyValue: function (sord, keyName, value, params) {

        var me = this;

        if (!Array.isArray(value)) {
          value = (value == undefined)
            ? [""]
            : String(value)
                .split(me.pilcrow)
                .filter(function (el) {
                  return el.trim();
                });
        }
        return this.setObjKeyValues(sord, keyName, value, params);
      },

      /**
       * Sets the values of an ObjKey for a field
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} keyName Name of the index field
       * @param {String[]} values
       * @param {Object} params Parameters
       * @param {Boolean} params.silent Silent
       * @return {de.elo.ix.client.ObjKey} The changed ObjKey
       */
      setObjKeyValues: function (sord, keyName, values, params) {
        var me = this,
            newObjKey, objKeys, line, key, i, value;

        params = params || {};

        if (!sord) {
          throw "Sord is missing";
        }

        if (!keyName) {
          throw "Object key name is empty";
        }

        values = values || [""];

        if (params.fillString) {
          for (i = 0; i < values.length; i++) {
            value = values[i] + "";
            if (value.length < params.fillString.length) {
              value += params.fillString.substr(value.length);
            }
            values[i] = value;
          }
        }

        key = this.getObjKey(sord, keyName);
        if (key) {
          key.data = values;
        } else {

          // in some cases objKey array doesn't match mask definition.
          line = me.getDocMaskLine(sord.mask, keyName) || me.getHiddenLine(keyName);
          if (line) {
            me.logger.debug("ObjKey '" + keyName + "' does not exist. Adding ObjKey to list.");
            newObjKey = new ObjKey();
            newObjKey.id = line.id;
            newObjKey.name = keyName;
            newObjKey.data = values;
            objKeys = Array.prototype.slice.call(sord.objKeys);
            objKeys.push(newObjKey);
            sord.objKeys = objKeys;
            key = newObjKey;
          } else {
            if (!params.silent) {
              throw "ObjKey '" + keyName + "' not found.";
            }
            return;
          }
        }
        return key;
      },

      /**
       * Retrieves (and caches) the definition of document masks by their name
       * @param {String} name
       * @param {String} language
       * @returns {de.elo.ix.client.DocMask} mask
       */
      getDocMask: function (name, language) {
        var me = this,
            languageCache, _result;

        me.logger.enter("getDocMask", { name: name, language: language });

        if (!name && (name !== 0)) { // Issue BS-799: second check is for the special case if some of our scripts call this function with an integer (which can be zero)
          throw "Document mask name is empty";
        }

        language = language || ixConnect.loginResult.clientInfo.language;

        if (!me.docMaskCache.containsKey(language)) {
          me.docMaskCache.put(language, sol.create("sol.common.Cache"));
        }

        languageCache = me.docMaskCache.get(language);

        if (!languageCache.containsKey(name)) {
          languageCache.put(name, ixConnect.ix().checkoutDocMask(name + "", DocMaskC.mbAll, LockC.NO));
        }

        _result = languageCache.get(name);
        me.logger.exit("getDocMask", _result + "");
        return _result;
      },

      /**
       * Reads document mask names
       * @param {Object} params Parameters
       * @param {Object} params.allMasks if true, return all docmasks
       * @param {Object} params.filters Filters
       * @param {String} params.filters.nameTranslationKeyPrefix Name translation key prefix filter
       * @return {de.elo.ix.client.MaskName[]}
       */
      getDocMaskNames: function (params) {
        var maskNames = [],
            editInfoZ, editInfo, i, maskName;

        params = params || {};

        editInfoZ = new EditInfoZ(EditInfoC.mbMaskNames, new SordZ());
        editInfo = ixConnect.ix().createSord(params.allMasks === true ? null : "1", "", editInfoZ);
        for (i = 0; i < editInfo.maskNames.length; i++) {
          maskName = editInfo.maskNames[i];
          if (params.filters) {
            if (params.filters.nameTranslationKeyPrefix) {
              if (String(maskName.nameTranslationKey).indexOf(params.filters.nameTranslationKeyPrefix) == 0) {
                maskNames.push(maskName);
              }
            }
          } else {
            maskNames.push(maskName);
          }
        }
        return maskNames;
      },

      /**
       * Returns the GUID of a doc mask
       * @param {String} name Doc mask name
       * @returns {String} GUID
       */
      getDocMaskGuid: function (name) {
        var me = this,
            docMask;
        docMask = me.getDocMask(name);
        return docMask ? String(docMask.guid) : "";
      },

      /**
       * Checks, if a sord has the specified mask
       * @param {de.elo.ix.client.Sord} sord
       * @param {String} maskName The original mask name
       * @return {Boolean}
       */
      hasDocMask: function (sord, maskName) {
        var me = this,
            docMask;
        if (!me.isSord(sord) || !maskName) {
          return false;
        }
        docMask = me.getDocMask(maskName);
        return sord && (sord.mask === docMask.id);
      },

      /**
       * Gets the field information of a specific mask field
       * @param {String} maskName Name of the mask
       * @param {String} fieldName Name of the field
       * @return {de.elo.ix.client.DocMaskLine}
       */
      getDocMaskLine: function (maskName, fieldName) {
        var me = this,
            docMask, i, line;

        docMask = me.getDocMask(maskName);

        for (i = 0; i < docMask.lines.length; i++) {
          line = docMask.lines[i];
          if (line.key == fieldName) {
            return line;
          }
        }
      },

      /**
       * @private
       * Returns an hidden line object
       * @param {String} keyName Key name
       * @return {Objekt} line Line
       * @return {String} line.id Line ID
       * @return {String} line.name Key name
       */
      getHiddenLine: function (keyName) {
        var me = this,
            hiddenLine;

        if (!me.hiddenLines) {
          me.hiddenLines = {};
          me.hiddenLines[DocMaskLineC.NAME_FILENAME + ""] = { id: DocMaskLineC.ID_FILENAME + "", name: DocMaskLineC.NAME_FILENAME };
          me.hiddenLineExists("NAME_LINK") && (me.hiddenLines[DocMaskLineC.NAME_LINK + ""] = { id: DocMaskLineC.ID_LINK + "", name: DocMaskLineC.NAME_LINK });
          me.hiddenLineExists("NAME_MAINSCALE") && (me.hiddenLines[DocMaskLineC.NAME_MAINSCALE + ""] = { id: DocMaskLineC.ID_MAINSCALE + "", name: DocMaskLineC.NAME_MAINSCALE });
          me.hiddenLineExists("NAME_PERSONALDATA_DELETEAT") && (me.hiddenLines[DocMaskLineC.NAME_PERSONALDATA_DELETEAT + ""] = { id: DocMaskLineC.ID_PERSONALDATA_DELETEAT + "", name: DocMaskLineC.NAME_PERSONALDATA_DELETEAT });
          me.hiddenLineExists("NAME_PERSONALDATA_UID") && (me.hiddenLines[DocMaskLineC.NAME_PERSONALDATA_UID + ""] = { id: DocMaskLineC.ID_PERSONALDATA_UID + "", name: DocMaskLineC.NAME_PERSONALDATA_UID });
        }

        hiddenLine = me.hiddenLines[keyName];

        return hiddenLine;
      },

      /**
       * Checks if a hidden line exists
       * @param {String} constantName Constant name
       */
      hiddenLineExists: function (constantName) {
        var docMaskLineC, docMaskLineCClass, fields, i, field;

        docMaskLineC = new DocMaskLineC();
        docMaskLineCClass = docMaskLineC.getClass();

        fields = docMaskLineCClass.getDeclaredFields();

        for (i = 0; i < fields.length; i++) {
          field = fields[i];
          if (field.name == constantName) {
            return true;
          }
        }

        return false;
      },

      /**
       * Checks wether a mask exists
       * @param {String} maskName
       * @return {Boolean}
       */
      docMaskExists: function (maskName) {
        if (!maskName) {
          throw "Mask name is empty";
        }
        try {
          ixConnect.ix().checkoutDocMask(maskName + "", DocMaskC.mbAll, LockC.NO);
          return true;
        } catch (ex) {
          return false;
        }
      },

      /**
       * Retrieves values from a dynamic keyword list.
       *
       * Returns the values from the KWL associated with the REMINDER_PERIOD_UNIT field
       *
       *     sol.common.SordUtils.getDynamicKeywordlistValue("Contract", "REMINDER_PERIOD_UNIT");
       *
       * Returns the values from the KWL associated with the REMINDER_PERIOD_UNIT field and containing the string 'month'
       *
       *     sol.common.SordUtils.getDynamicKeywordlistValue("Contract", "REMINDER_PERIOD_UNIT", { data: "month" });
       *
       * Returns the values from the KWL associated with the REMINDER_PERIOD_UNIT field and the data from column 2
       *
       *     sol.common.SordUtils.getDynamicKeywordlistValue("Contract", "REMINDER_PERIOD_UNIT", { returnColumn: 2 });
       *
       * Returns the values from the KWL associated with the REMINDER_PERIOD_UNIT field and the data from column 2 filtering only thoase containing 'M' in column 1
       *
       *     sol.common.SordUtils.getDynamicKeywordlistValue("Contract", "REMINDER_PERIOD_UNIT", { data: "M", filterColumn: 0, returnColumn: 2 });
       *
       * @param {String} maskName The mask name used to determine the dynamic keyword list
       * @param {String} key The field which has the dynamic keyword list
       * @param {Object} params (optional)
       * @param {String} params.data (optional) lookup data (used to filter the result on the serverside, if supported by the KWL, or on clientside, if `returnColumn` and `filterColumn` are defined)
       * @param {Number} params.returnColumn (optional) If set, the content of this column will be returned
       * @param {Number} params.filterColumn (optional) If set (in addition to a return column), the result will be filtered on the clientside on the KWL column with this index (using `params.data`)
       * @return {String[]}
       */
      getDynamicKeywordlistValue: function (maskName, key, params) {
        var me = this,
            keywordsDynamicInfo = new KeywordsDynamicInfo(),
            sord = new Sord(),
            objKey = new ObjKey(), foreignObjKey = new ObjKey(),
            result = [], objKeys = [],
            columnMode = (params && (typeof params.returnColumn === "number")),
            docMaskLine, keywordsResult, i, max, keyIndex;

        key = new java.lang.String(key);

        objKey.name = key;
        objKey.data = (params && params.data && (typeof params.filterColumn !== "number")) ? [params.data] : [];
        objKeys.push(objKey);

        if (params && params.useForeignKey && (params.useForeignKey.key && params.useForeignKey.value)) {
          foreignObjKey.name = params.useForeignKey.key;
          foreignObjKey.data = [params.useForeignKey.value];
          objKeys.push(foreignObjKey);
        }

        sord.objKeys = objKeys;

        docMaskLine = me.getDocMaskLine(maskName, key);

        if (!docMaskLine) {
          throw "Can't find document mask line: maskName=" + maskName + ", key=" + key;
        }

        keywordsDynamicInfo.sord = sord;
        keywordsDynamicInfo.maskLineFocus = docMaskLine;

        keywordsResult = ixConnect.ix().checkoutKeywordsDynamic(keywordsDynamicInfo);

        if (columnMode) {
          keyIndex = params.returnColumn;
        } else {
          for (i = 0, max = keywordsResult.keyNames.size(); i < max; i++) {
            if (keywordsResult.keyNames.get(i).equals(key)) {
              keyIndex = i;
              break;
            }
          }
        }

        for (i = 0, max = keywordsResult.table.size(); i < max; i++) {
          if (!columnMode || !params.data || (typeof params.filterColumn !== "number") || (sol.common.StringUtils.startsWith(keywordsResult.table.get(i).get(params.filterColumn) + "", params.data))) {
            result.push(keywordsResult.table.get(i).get(keyIndex) + "");
          }
        }

        return result;
      },

      /**
       * Returns the key of a localized keyword list entry
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} fieldDef Field definition
       * @param {Object} config Configuration
       * @param {String} config.localizedKwlSeparator Localized keyword list separator
       * @return {String}
       */
      getLocalizedKwlKey: function (sord, fieldDef, config) {
        var me = this,
            value, separator, separatorPos;
        if (!sord) {
          throw "Sord is empty";
        }
        if (!fieldDef) {
          throw "Field definition is empty";
        }

        config = config || {};
        separator = config.localizedKwlSeparator || "-";

        value = String(me.getValue(sord, fieldDef));

        separatorPos = value.indexOf(separator);
        if (separatorPos < 0) {
          return value;
        }
        return value.substring(0, separatorPos).trim();
      },

      /**
       * Returns the localized kwl entry
       * @param {String} key Key
       * @param {Object} config Configuration
       * @param {String} config.scriptName Script name
       * @return {String}
       */
      getLocalizedKwlEntry: function (key, config) {
        var keywordsDynamicInfo, keywordsResult, entry;

        if (!key) {
          throw "Key is empty";
        }

        config = config || {};

        if (!config.localizedKwlScript) {
          throw "Localized keyword list script name is emtpy";
        }

        keywordsDynamicInfo = new KeywordsDynamicInfo();
        keywordsDynamicInfo.mapData = { $KEY: key };
        keywordsDynamicInfo.mapLineFocus = "$KEY";
        keywordsDynamicInfo.mapScriptName = config.localizedKwlScript;

        keywordsResult = ixConnect.ix().checkoutKeywordsDynamic(keywordsDynamicInfo);

        if (keywordsResult.table.size() != 1) {
          return "";
        }

        entry = String(keywordsResult.table.get(0).get(2));

        return entry;
      },

      /**
       * 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 me = this,
            templateSord;

        me.logger.enter("getTemplateSord", arguments);
        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
            }
          }
        });
        me.logger.exit("getTemplateSord");
        return templateSord;
      },

      /**
       * Creates a statistic sord from a Sord (see {@link sol.common.ObjectFormatter.StatisticSord StatisticSord}).
       * @param {de.elo.ix.client.Sord} sord
       * @return {Object}
       */
      getStatisticSord: function (sord) {
        var me = this,
            statisticSord;

        me.logger.enter("getStatisticSord", arguments);
        statisticSord = sol.common.ObjectFormatter.format({
          sord: {
            formatter: "sol.common.ObjectFormatter.StatisticSord",
            data: sord,
            config: {
              sordKeys: ["id", "guid", "maskName", "name", "desc", "IDateIso", "XDateIso", "ownerName"],
              objKeys: ["VENDOR_NAME", "INVOICE_DATE", "INVOICE_CASH_DISCOUNT_AMOUNT"]
            }
          }
        });
        me.logger.exit("getStatisticSord");
        return statisticSord;
      },

      /**
       * Returns the display repository path
       * @param {de.elo.ix.client.Sord} sord
       * @param {Object} params Parameters
       * @param {String} [params.separator="/"] Separator
       * @param {Boolean} [params.withName=true] If true the name of the Sord will be appended
       * @return {String}
       */
      getDisplayRepoPath: function (sord, params) {
        var me = this,
            displayRepoPath;

        if (!sord) {
          throw "Sord is empty";
        }
        if (!sord.refPaths) {
          throw "Property 'sord.refPaths is empty'";
        }

        params = params || {};
        params.separator = params.separator || "/";
        params.withName = (typeof params.withName == "undefined") ? true : params.withName;

        displayRepoPath = sord.refPaths[0].pathAsString;
        displayRepoPath = sol.common.StringUtils.replaceAll(displayRepoPath, me.pilcrow, params.separator);
        if (params.withName) {
          displayRepoPath += params.separator + sord.name;
        }

        return displayRepoPath;
      },

      /**
       * Creates a Sord
       *
       * Backward-comptabilility added for createSord(maskId, params)
       *
       * @param {Object} params Parameters
       * @param {String} params.mask Mask
       * @param {String} params.name Name
       * @param {String} [params.parentId="1"] Parent ID
       * @param {String} params.sortOrder Sort order
       * @param {String} params.documentContainer Container document
       * @return {de.elo.ix.client.Sord} Sord
       */
      createSord: function (params) {
        var sord;
        params = params || {};

        // backward-compatibility
        if (arguments.length == 2) {
          params = arguments[1];
          params.mask = {
            mask: arguments[0]
          };
        }

        if (!params.mask) {
          throw "Mask ID is empty";
        }
        params.parentId = params.parentId || "1";
        sord = ixConnect.ix().createSord(params.parentId, params.mask, EditInfoC.mbSord).sord;

        if (typeof params.name != "undefined") {
          sord.name = params.name;
        }

        if (typeof params.sortOrder != "undefined") {
          sord.details.sortOrder = params.sortOrder;
        }

        if (typeof params.documentContainer != "undefined") {
          sord.details.documentContainer = params.documentContainer;
        }

        return sord;
      },

      /**
       * Clones a sord.
       * @param {de.elo.ix.client.Sord} srcSord Source sord
       * @param {Object} params (optional) Parameters
       * @param {de.elo.ix.client.Sord} params.dstSord (optional) Destination sord
       * @param {String} params.dstMask (optional) Destination mask
       * @param {de.elo.ix.client.Sord} params.dstParentId (optional) Destination parent ID. Hint: parameter is mandatory if no `dstSord` is configured
       * @param {String[]} [params.memberNames=["name"]] (optional) Member names to copy
       * @param {String[]} params.detailMemberNames (optional) Detail member names to copy, e.g. `sortOrder`
       * @param {String[]} params.objKeyNames (optional) Object key names to copy
       * @param {Boolean} [params.inheritDestinationAcl=false] (optional) If `true` (and the target is a sord) the ACL of the target will be inherited to the cloned sord. Hint: to copy the ACL of the source sord use member `aclItems` (but `inheritDestinationAcl` has priority).
       * @return {de.elo.ix.client.Sord} Sord
       */
      cloneSord: function (srcSord, params) {
        var me = this,
            dstSord, dstMask, memberName, detailMemberName, now, i, parentSord, objKey, objKeyName, values, conn;

        if (!srcSord) {
          throw "Source Sord is emtpy";
        }

        params = params || {};
        params.memberNames = params.memberNames || ["name"];

        conn = params.conn || ixConnect;

        if (params.dstSord) {
          dstSord = new Sord(params.dstSord);
          dstSord.id = -1;
          dstSord.guid = "";
          dstSord.ownerId = ixConnect.loginResult.user.id;
          dstSord.ownerName = "";
          now = me.nowIsoForConnection(conn);
          dstSord.IDateIso = now;
          dstSord.XDateIso = now;
        } else {
          dstMask = params.dstMask || srcSord.mask;
          dstSord = me.createSord({ mask: dstMask, parentId: params.dstParentId });
        }

        for (i = 0; i < params.memberNames.length; i++) {
          memberName = params.memberNames[i];
          dstSord[memberName] = srcSord[memberName];
        }

        if (params.detailMemberNames) {
          for (i = 0; i < params.detailMemberNames.length; i++) {
            detailMemberName = params.detailMemberNames[i];
            dstSord.details[detailMemberName] = srcSord.details[detailMemberName];
          }
        }

        if (params.dstParentId) {
          if (params.dstParentId != "0") {
            parentSord = ixConnect.ix().checkoutSord(params.dstParentId, SordC.mbMin, LockC.NO);
            if (params.inheritDestinationAcl) {
              dstSord.aclItems = parentSord.aclItems;
            }
          }
          dstSord.parentId = (parentSord) ? parentSord.id : "0";
        }

        if (!params.objKeyNames || (params.objKeyNames.length > 0)) {
          for (i = 0; i < dstSord.objKeys.length; i++) {
            objKey = dstSord.objKeys[i];
            objKeyName = String(objKey.name);
            if (objKeyName == "" || (params.objKeyNames && (params.objKeyNames.indexOf(objKeyName) < 0))) {
              continue;
            }
            if (objKeyName != "") {
              values = me.getObjKeyValues(srcSord, objKeyName);
              me.setObjKeyValues(dstSord, objKeyName, values);
            }
          }
        }

        return dstSord;
      },

      /**
       * Adds rights
       * @param {de.elo.ix.client.Sord} sord Sord
       * @param {Object} params Parameters
       * @param {Array} params.users Users
       * @param {Object} params.rigths Rights, e.g. { r: true, w: true, d: true, e: true, l: true }
       */
      addRights: function (sord, params) {
        var accessCode, users, userAcls, newAclItems;

        if (!params) {
          throw "Rights configuration is empty";
        }
        if (!params.users) {
          throw "Users are empty";
        }

        params = params || {};

        users = params.users.map(function (userName) {
          if (userName == "$CURRENTUSER") {
            return String(ixConnect.loginResult.user.name);
          }
          return userName;
        });

        params.rights = params.rights || { r: true, w: true, d: true, e: true, l: true, p: true };

        accessCode = sol.common.AclUtils.createAccessCode(params.rights);
        userAcls = sol.common.AclUtils.retrieveUserAcl(users, accessCode);
        if (userAcls) {
          newAclItems = Array.prototype.slice.call(sord.aclItems);
          userAcls.forEach(function (userAcl) {
            newAclItems.push(userAcl);
          });
        }
        sord.aclItems = newAclItems;
      },

      /**
       * Changes the sord mask
       * @param {de.elo.ix.client.Sord} sord Sord
       * @param {Number|String} newMask New mask ID or name
       * @param {de.elo.ix.client.IXConnection} ixConnection (optional) contains the given IX-Connection
       * @return {de.elo.ix.client.Sord}
       */
      changeMask: function (sord, newMask, ixConnection) {
        var me = this,
            myConnection = ixConnection || ixConnect,
            changedSord;

        if (!sord) {
          throw "Sord is empty";
        }

        if (typeof newMask == "undefined") {
          throw "New mask is empty";
        }

        changedSord = myConnection.ix().changeSordMask(sord, newMask, EditInfoC.mbSord).sord;

        me.logger.debug(["conn.username={0}, changedSord={1}", myConnection.loginResult.user.name, changedSord.name]);

        return changedSord;
      },

      /**
       * Get links
       * @param {de.elo.ix.client.Sord} sord Sord
       * @return {Array} Object IDs
       */
      getLinks: function (sord) {
        var i,
            linksObj = {},
            links = [],
            objId;

        if (!sord) {
          throw "Sord is empty";
        }

        for (i = 0; i < sord.linksComeIn.length; i++) {
          linksObj[sord.linksComeIn[i].id + ""] = 1;
        }

        for (i = 0; i < sord.linksGoOut.length; i++) {
          linksObj[sord.linksGoOut[i].id + ""] = 1;
        }

        for (objId in linksObj) {
          links.push(objId);
        }

        return links;
      },

      /**
       * Returns now as ISO date considering the time zone
       * @param {de.elo.ix.client.IXConnection} [conn=ixConnect]
       * @param {Object} params Parameters
       * @param {Boolean} [params.startOfDay=false] (optional) Start of day
       * @return {String} ISO date
       */
      nowIsoForConnection: function (conn, params) {
        var me = this,
            nowIso, timeZone;
        conn = conn || ixConnect;
        params = params || {};
        timeZone = conn.loginResult.clientInfo.timeZone + "";
        params.utcOffset = me.getTimeZoneOffset(timeZone);
        nowIso = sol.common.DateUtils.nowIso(params);
        return nowIso;
      },

      /**
       * @private
       * Gets the time zone offset
       * @param {String} timeZoneString Time zone string
       * @return {String} Offset
       */
      getTimeZoneOffset: function (timeZoneString) {
        var timeZone, utcOffset, now;
        timeZone = java.util.TimeZone.getTimeZone(timeZoneString);
        now = new java.util.Date();
        utcOffset = timeZone.getOffset(now.time) / 1000 / 60;
        return utcOffset;
      },

      /**
       * Returns the field name index
       * @param {String} fieldName Field name
       * @returns {String}
       */
      getFieldNameIndex: function (fieldName) {
        if (!fieldName) {
          return "";
        }
        var pos = fieldName.search(/\d+$/);
        if (pos > 0) {
          return parseInt(fieldName.substring(pos), 10);
        }
        return "";
      },

      /**
       * Returns the ESW content
       * @param {String} objId Object ID
       * @param {String} params Parameters
       * @param {Object} params.timeZone Timezone, e.g. `GMT`
       * @return {String} ESW content
       */
      getEsw: function (objId, params) {
        var savedTimeZone,
            editInfo, eswOptions, fileDataArr, fileData, esw;

        if (!objId) {
          throw "Object ID is empty";
        }

        params = params || {};
        if (params.timeZone) {
          savedTimeZone = ixConnect.loginResult.clientInfo.timeZone;
          ixConnect.loginResult.clientInfo.timeZone = params.timeZone;
        }

        editInfo = ixConnect.ix().checkoutSord(objId, EditInfoC.mbSord, LockC.NO);
        eswOptions = new EditInfoEswOptions();
        fileDataArr = ixConnect.ix().getESWFromEditInfo([editInfo], eswOptions);
        fileData = fileDataArr[0];
        esw = new java.lang.String(fileData.data, "UTF-8") + "";

        if (savedTimeZone) {
          ixConnect.loginResult.clientInfo.timeZone = params.timeZone = savedTimeZone;
        }

        return esw;
      },

      /**
       * Returns blob data from a map entry
       * @param {de.elo.ix.client.KeyValue} mapEntry Map entry
       * @param {Object} params Parameters
       * @param {String} [params.returnType=String] returnType, e.g. `String`
       * @param {String} [params.encoding=UTF-8] encoding, e.g. `UTF-8`
       * @return {String}
       */
      getBlobDataFromMapEntry: function (mapEntry, params) {
        var fileData, stringValue;

        if (!mapEntry || !mapEntry.blobValue) {
          return;
        }

        fileData = mapEntry.blobValue;

        if (!fileData.stream) {
          return;
        }

        params = params || {};
        params.returnType = params.returnType || "String";
        params.encoding = params.encoding || "UTF-8";

        if (params.returnType == "String") {
          stringValue = Packages.org.apache.commons.io.IOUtils.toString(fileData.stream, params.encoding) + "";
          fileData.stream.close();
          return stringValue;
        }
      },

      /**
       * Returns the internal date for `iDate` and `xDate`
       * @param {String} isoDate ISO date
       * @param {Object} params Parameters
       * @param {Object} params.conn Connection
       * @param {String} Internal date
       */
      getInternalDate: function (isoDate, params) {
        var me = this,
            ELODATE_1970_01_01_UTC,
            conn, timeZone, utcOffset, date, systemMillis, internalDateInteger, internalDateString;

        ELODATE_1970_01_01_UTC = 36819360;

        params = params || {};

        conn = params.conn || ixConnect;

        timeZone = conn.loginResult.clientInfo.timeZone + "";
        utcOffset = me.getTimeZoneOffset(timeZone);

        if (isoDate) {
          date = Packages.org.apache.commons.lang3.time.DateUtils.parseDate(isoDate, ["yyyyMMddHHmmss", "yyyyMMdd"]);
        } else {
          date = new java.util.Date();
        }

        systemMillis = date.getTime();

        internalDateInteger = parseInt((systemMillis / 60 / 1000) + ELODATE_1970_01_01_UTC + utcOffset, 10);
        internalDateString = internalDateInteger + "";

        return internalDateString;
      },

      /**
       * Reads map entries for the defined `objId` (or `mapId`) and returns them as an object
       * @param {Object} config Configuration
       * @param {Array} config.keys Map-keys which should be returned
       * @param {String} [config.mapId=config.objId] Either `mapId` or `objId` must be passed. The specific map for the `mapId` or `objId` will be read.
       * @param {String} config.objId Object ID
       * @param {de.elo.ix.client.MapDomainDataC} [config.domain=MapDomainC.DOMAIN_SORD] Map domain
       * @param {de.elo.ix.client.IXConnection} [params.connection=ixConnect] Index server connection
       */
      getMapEntriesAsObject: function (config) {
        var mapId,
            mapObj = {},
            domain, keys, connection, keyValues, i, entry;

        config = config || {};
        mapId = config.mapId || config.objId;
        domain = config.domain || MapDomainC.DOMAIN_SORD;

        if (!mapId) {
          throw "Map ID is missing";
        }

        keys = config.keys || [];
        connection = config.connection || ixConnect;

        keyValues = connection.ix().checkoutMap(domain, mapId, keys, LockC.NO).items;

        for (i = 0; i < keyValues.length; i++) {
          entry = keyValues[i];
          mapObj[entry.key + ""] = entry.value + "";
        }

        return mapObj;
      }
    });