    //@include lib_Class.js

    /**
     * @class sol.common.Instance
     * @extends sol.Base
     * @singleton
     *
     * @experimental
     * This is an experimental new functionality, which may be removed in future versions.
     *
     * This class provides basic functionality to create solution instances.
     *
     * It can be used to create single independent instances of the defined instanceDefinition
     * and addresses misuses and / or misunderstandings regarding sol.define and sol.create.
     *
     * Contrary to sol.define, properties defined via sol.common.instance.define are not properties
     * defined as "class properties" which may be shared with other "class instances" of the same class
     * or of classes which extend the class, but are properties defined as "instance properties" which,
     * if not explicit set as "class properties", are only available and accessable within the same
     * "instance".
     *
     *
     * # Defining instances - basic syntax
     *
     * Every instance is represented by an instance name that should include a namespace and the instance
     * definition.
     * The instance definition is a js object that represents the contents of that instance. Functions and
     * properties that are part of the instanceDefinition will be part of the instance.
     *
     *     sol.common.instance.define(instanceName, intanceDefinition);
     *
     * ## initialize - Function
     *
     * The initialize function will be called during the creation of an instance with the provided
     * configuration.
     * Due to the fact that all instances (except "sol.common.instance.logger") extend at least
     * "sol.common.instance.base", every instance does have an initialize function.
     * "sol.common.instance.base"'s initialize functions applies the properties of then configuration
     * to the instance.
     *
     * @eloall
     */
    sol.define("sol.common.instance", {
      singleton: true,
      $definedInstances: {},
      $definedSingletons: {},
      $globalParent: "sol.common.instance.base",
      baseInstances: [
        "sol.common.instance.base",
        "sol.common.instance.logger"
      ],
      setSingleton: function (name, singletonDefinition) {
        var me = this;

        me.$definedSingletons[name] = singletonDefinition;
      },
      getSingleton: function (name, _options) {
        var me = this;

        if (!me.$definedSingletons[name]) {
          me.logger.warn("could not get singleton instance definition of " + name);
        }
        return me.$definedSingletons[name];

      },
      setInstanceDefinition: function (name, instanceDefinition) {
        var me = this;

        me.$definedInstances[name] = instanceDefinition;
      },
      getInstanceDefinition: function (name, _options) {
        var me = this;

        if (!me.$definedInstances[name]) {
          me.logger.warn("could not get instance definition of " + name);
        }
        return me.clone(me.$definedInstances[name]);
      },
      define: function (name, instanceDefinition, config) {
        var me = this,
            // clone input definition to prevent manipulation of the definition
            clonedDefinition = me.clone(instanceDefinition);

        clonedDefinition.$name = name;

        me.setInstanceDefinition(name, clonedDefinition);

        if (clonedDefinition.singleton) {
          me.setSingleton(name, me.create(name, config || {}));
        }
      },
      create: function (name, config, options) {
        var me = this,
            instanceDefinition,
            singletonDefinition,
            instance,
            defaultOptions = {
              onCreate: ["initialize"]
            },
            mixinsContainer,
            parent,
            elementsToMerge = [];

        options = options || defaultOptions;

        // check if singleton and return clone
        singletonDefinition = me.getSingleton(name, options);
        if (singletonDefinition) {
          // singletons will be created on define once an then only returned
          return singletonDefinition;
        }

        // get instanceDefinition
        instanceDefinition = me.getInstanceDefinition(name, options);
        if (!instanceDefinition) {
          throw "Could not create instance '" + name + "', please define instance first";
        }
        // create mixins
        mixinsContainer = me.createMixins(instanceDefinition, config, options) || null;
        if (mixinsContainer) {
          elementsToMerge = elementsToMerge.concat(mixinsContainer.mixins);
        }

        // create parent
        parent = me.createParent(instanceDefinition, config, options) || {};
        elementsToMerge.push(parent);

        // add instanceDefinition and merge to instance
        elementsToMerge.push(instanceDefinition);

        instance = me.merge(elementsToMerge, {});

        // set $super function and bind it ($super executes in its own context)
        instance.$super = me.$instanceSuper.bind({}, instance);

        if (mixinsContainer) {
          // call onCreate functions (generally "initialize") of mixin classes
          me.callMethodsOnInstance(instance, mixinsContainer.$initialize, config);
        }
        // call onCreate functions (generally "initialize") of this class
        me.callMethodsOnInstance(instance, options.onCreate, config);

        return instance;
      },
      createMixins: function (instanceDefinition, config, options) {
        var me = this,
            mixinOptions,
            mixins,
            exists = function (elem) {
              return !!elem;
            };

        if (instanceDefinition.mixins) {
          mixinOptions = me.clone(options) || {};
          mixinOptions.onCreate = [];
          mixins = (instanceDefinition.mixins || [])
            .map(function (mixinName) {
              return me.create(mixinName, config, mixinOptions);
            });

          return {
            $initialize: mixins.map(function (mixin) {
              return mixin.initialize;
            }).filter(exists),
            mixins: mixins.map(function (mixin) {
              mixin.initialize = undefined;
              return mixin;
            }).filter(exists)
          };
        }
      },
      createParent: function (instanceDefinition, config, options) {
        var me = this,
            parentOptions,
            parent;

        if (instanceDefinition.extend || me.baseInstances.indexOf(instanceDefinition.$name) == -1) {
          parentOptions = me.clone(options) || {};
          parentOptions.onCreate = [];
          parent = me.create(instanceDefinition.extend || me.$globalParent, config, parentOptions);
          parent.$parent = me.clone(parent);
          return parent;
        }
        return null;
      },
      /**
       *
       * @private
       * Finds attribute in parent instance.
       * If found attribute is a function, attribute will be called in instance context and
       * with given args as arguments. Calls to $super within the attribute can only access
       * itself and its own parents.
       * if found attribute is not a function, a cloned version of attribute will be returned.
       *
       * @param {*} instance the current instance (gets bound as first parameter within create)
       * @param {String} name name of the parent class (Optional)
       * @param {String} attributeName name of the attribute (Mandatory)
       * @param {*} args arguments to pass to function, if value at aParent[attributeName] is a function (optional)
       * @returns {*} the result of a function call or the value at the given attribute
       */
      $instanceSuper: function (instance, name, attributeName, args) {
        var me = this,
            self = sol.common.instance,
            result,
            parentContainer,
            currentSuperInstance;

        me.$currentParents = me.$currentParents || [];

        currentSuperInstance = me.$currentParents.length > 0
          ? me.$currentParents[me.$currentParents.length]
          : instance;

        parentContainer = self.getParentAttribute(currentSuperInstance.$parent, name, attributeName);

        if (parentContainer) {
          if (typeof parentContainer.attribute == "function") {
            // push $parent to last index of $currentParents so that all calls to $super
            // within the upcoming function call can only access itself and its own parents
            // this would not work with asynchronous calls
            me.$currentParents.push(parentContainer.$instance);
            // call of $super function
            result = parentContainer.attribute.apply(instance, Array.isArray(args) ? args : [args]);
            // call is finished, instances can be removed from $currentParents
            me.$currentParents.pop();
          } else {
            result = self.clone(parentContainer.attribute);
          }
          return result;
        }
      },
      getParentAttribute: function (parent, name, attributeName) {
        var me = this;

        if (!parent) {
          return null;
        }

        return ((name && parent.$name == name) || (!name && parent[attributeName]))
          ? parent[attributeName]
            ? { $instance: parent, attribute: parent[attributeName] }
            : null
          : me.getParentAttribute(parent.$parent, name, attributeName);
      },
      callMethodsOnInstance: function (instance, methods, args) {
        (methods || [])
          .forEach(function (method) {
            if (typeof method == "string") {
              if (typeof instance[method] == "function") {
                instance[method].apply(instance, Array.isArray(args) ? args : [args]);
              }
            } else if (typeof method == "function") {
              method.apply(instance, Array.isArray(args) ? args : [args]);
            }
          });
      },
      merge: function (sources, target) {
        var me = this;

        return (sources || [])
          .reduce(function (aTarget, aSource) {
            if (typeof aSource == "object") {
              Object.keys(aSource)
                .forEach(function (key) {
                  aTarget[key] = typeof aTarget[key] != "undefined"
                    ? me.merge([aSource[key]], aTarget[key])
                    : aSource[key] || aTarget[key];
                });
            } else {
              return aSource || aTarget;
            }
            return aTarget;
          }, target || {});
      },
      clone: function (obj) {
        var me = this,
            getType = function (any) {
              var intermediate;
              if (any !== any) {
                return "nan";
              }
              if (typeof any !== "object") {
                return typeof any;
              }
              if (typeof java !== "undefined" && any instanceof java.lang.String) {
                return "string";
              } else {
                intermediate = Object.prototype.toString.call(any);
                return intermediate.substring(8, intermediate.length - 1).toLowerCase();
              }
            },
            cloneArray = function (arr) {
              return arr.map(function (element) {
                return me.clone(element);
              });
            },
            cloneObj = function (anObject) {
              var toKeyValue = function (root, key) {
                return { key: key, value: root[key] };
              };

              return Object.keys(anObject)
                .map(toKeyValue.bind(null, anObject))
                .reduce(function (target, pair) {
                  target[pair.key] = me.clone(pair.value);
                  return target;
                }, {});
            };

        switch (getType(obj)) {
          case "array":
            return cloneArray(obj);
          case "object":
            return cloneObj(obj);
          case "function":
          case "string":
          case "boolean":
          case "number":
          case "nan":
          case "null":
          default:
            return obj;
        }
      }
    });

    /**
     * @class sol.common.instance.logger
     * @eloall
     * @experimental
     * This is an experimental new functionality, which may be removed in future versions.
     *
     * Please be aware that this class does not use sol.define  but sol.common.instance.define
     * and may be working slightly different.
     *
     * This instanceDefinition provides basic functionality to access and use the logger.
     */
    sol.common.instance.define("sol.common.instance.logger", {
      scope: "sol",
      debugEnabled: false,
      timings: {},
      pattern: {
        error: "[{{scope}}] {{msg}} : {{object}}",
        warn: "[{{scope}}] {{msg}} : {{object}}",
        info: "[{{scope}}] {{msg}} : {{object}}",
        debug: "[{{scope}}] {{msg}} : {{object}}",
        enter: "[{{scope}}] ENTER {{msg}} : {{object}}",
        exit: "[{{scope}}] EXIT {{msg}} : {{time}}ms : {{object}}"
      },
      initialize: function (config) {
        var me = this;
        config = config || {};
        me.scope = config.scope || me.scope;

        me.setLogger(config);
        me.setDebugEnabled(typeof me.logger.isDebugEnabled == "function" ? me.logger.isDebugEnabled : false);
      },
      setLogger: function (config) {
        var me = this;

        if (config.logger) {
          me.logger = config.logger;
        } else {
          me.logger = (typeof console === "undefined" || typeof Graal !== "undefined") ? log : console;
        }
      },
      setDebugEnabled: function (enabled) {
        var me = this;
        me.debugEnabled = enabled;
      },
      error: function (msg, ex) {
        var me = this;

        me.logMessage(msg, ex ? ex : "", "error");
      },
      warn: function (msg, ex) {
        var me = this;

        me.logMessage(msg, ex ? ex : "", "warn");
      },
      info: function (msg, obj) {
        var me = this;
        me.logMessage(msg, me.stringify(obj) || "", "info");
      },
      debug: function (msg, obj) {
        var me = this;

        if (me.debugEnabled) {
          me.logMessage(msg, me.stringify(obj) || "", "debug", "info");
        }
      },
      enter: function (functionName, obj) {
        var me = this;

        if (me.debugEnabled) {
          me.setEnterTime(functionName);
          me.logMessage(functionName, me.stringify(obj) || "", "enter", "info");
        }
      },
      exit: function (functionName, obj) {
        var me = this;

        if (me.debugEnabled) {
          me.logMessage(functionName, me.stringify(obj) || "", "exit", "info");
        }
      },
      setEnterTime: function (functionName) {
        var me = this;
        me.enterTime = me.enterTime || {};
        me.enterTime[functionName] = Date.now();
      },
      getDuration: function (functionName) {
        var me = this,
            enterTime = me.enterTime[functionName],
            duration;

        me.enterTime[functionName] = undefined;

        if (enterTime) {
          duration = Date.now() - enterTime;
          if (duration < 0) {
            duration = 0;
          }
          return duration;
        } else {
          return -1;
        }
      },
      logMessage: function (msg, objectString, patternString, loggerFunction) {
        var me = this,
            message = me.pattern[patternString]
              .replace("{{scope}}", me.scope)
              .replace("{{msg}}", me.format(msg))
              .replace("{{object}}", objectString)
              .replace(/ : $/, "");

        if (patternString == "exit") {
          message = message.replace("{{time}}", me.getDuration(msg));
        }

        me.logger[loggerFunction || patternString](message);
      },
      format: function (msg) {
        var params;
        if (Object.prototype.toString.call(msg) === "[object Array]") {
          params = msg.slice(1);

          return msg[0].replace(/\{(\d+)\}/g, function (match, number) {
            return (typeof params[number] !== "undefined") ? params[number] : match;
          });
        }
        return msg;
      },
      stringify: function (obj) {
        var objType, str;
        if (typeof obj === "string") {
          return obj;
        }
        objType = Object.prototype.toString.call(obj);
        if ((objType == "[object Arguments]") || (objType == "[object JavaObject]")) {
          return "";
        }

        try {
          str = JSON.stringify(obj, function (key, value) {
            if (value instanceof java.lang.String) {
              return String(value);
            }
            if (value && value.getClass) {
              return String(value.toString());
            }
            return value;
          }) || "";

          return str;
        } catch (ex) {
          return typeof obj;
        }
      }
    });

    /**
     * @class sol.common.instance.base
     * @eloall
     * @experimental
     * This is an experimental new functionality, which may be removed in future versions.
     *
     * Please be aware that this instance does not use sol.define  but sol.common.instance.define
     * and may be working slightly different.
     *
     * This instanceDefinition applies all properties of config to the instance.
     * It is the superinstance of every class except sol.common.instance.logger.
     * If its initialize or toJSON function is overwritten by a child instance,
     * the child instance function has to call $super to execute these basic functions.
     */
    sol.common.instance.define("sol.common.instance.base", {
      toJSON: function () {
        var me = this;
        return Object.keys(me)
          .reduce(
            function (target, key) {
              if (key.indexOf("$") == 0) {
                return target;
              }
              target[key] = me[key];
              return target;
            }
            , {});
      },
      initialize: function (config) {
        var me = this,
            reservedProperties = [
              "extend",
              "requiredConfig",
              "singleton",
              "$super",
              "$name",
              "$parent",
              "CONST",
              "$instances"
            ];

        Object.keys(config)
          .forEach(function (property) {
            if (config.hasOwnProperty(property)) {
              if (typeof me[property] == "function" && typeof config[property] != "function") {
                throw "[" + me.$name + "] Illegal overriding internal function with a value: " + property + ". Existing functions cannot be overriden with non functional values using sol.common.instance.create().";
              } else if (property.indexOf("$") == 0 || reservedProperties.indexOf(property) != -1) {
                throw "[" + me.$name + "] Illegal overriding internal object value: " + property + ". Reserved words " + reservedProperties + " and all words starting with '$' are protected and should not be set using sol.common.instance.create().";
              }
              me[property] = config[property];
            }
          });
      }
    });