UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

363 lines (306 loc) 9.16 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2007-2008 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) ************************************************************************ */ /** * Registration for all instances of qooxdoo classes. Mainly * used to manage them for the final shutdown sequence and to * use weak references when connecting widgets to DOM nodes etc. * * @ignore(qx.dev, qx.dev.Debug.*) */ qx.Bootstrap.define("qx.core.ObjectRegistry", { /* ***************************************************************************** STATICS ***************************************************************************** */ statics : { /** * @type {Boolean} Whether the application is in the shutdown phase * @deprecated {6.0} shutdown is not a valid mechanism to terminate apps * */ inShutDown : false, /** @type {Map} Internal data structure to store objects */ __registry : {}, /** @type {Integer} Next new hash code. */ __nextHash : 0, /** @type {Array} List of all free hash codes */ __freeHashes : [], /** @type {String} Post id for hash code creation. */ __postId : "", /** @type {Map} Object hashes to stack traces (for dispose profiling only) */ __stackTraces : {}, /** * Registers an object into the database. This adds a hashcode * to the object (if not already done before) and stores it under * this hashcode. You can access this object later using the hashcode * by calling {@link #fromHashCode}. * * All registered objects are automatically disposed on application * shutdown. Each registered object must at least have a method * called <code>dispose</code>. * * @param obj {Object} Any object with a dispose() method */ register : function(obj) { var registry = this.__registry; if (!registry) { return; } var hash = obj.$$hash; if (hash == null) { // Create new hash code var cache = this.__freeHashes; if (cache.length > 0 && !qx.core.Environment.get("qx.debug.dispose")) { hash = cache.pop(); } else { hash = (this.__nextHash++) + this.__postId; } // Store hash code obj.$$hash = hash; if (qx.core.Environment.get("qx.debug.dispose")) { if (qx.dev && qx.dev.Debug && qx.dev.Debug.disposeProfilingActive) { this.__stackTraces[hash] = qx.dev.StackTrace.getStackTrace(); } } } if (qx.core.Environment.get("qx.debug")) { if (!obj.dispose) { throw new Error("Invalid object: " + obj); } } registry[hash] = obj; }, /** * Removes the given object from the database. * * @param obj {Object} Any previously registered object */ unregister : function(obj) { var hash = obj.$$hash; if (hash == null) { return; } var registry = this.__registry; if (registry && registry[hash]) { delete registry[hash]; this.__freeHashes.push(hash); } // Delete the hash code try { delete obj.$$hash; } catch(ex) { // IE has trouble directly removing the hash // but it's ok with using removeAttribute if (obj.removeAttribute) { obj.removeAttribute("$$hash"); } } }, /** * Returns an unique identifier for the given object. If such an identifier * does not yet exist, create it. * * @param obj {Object} the object to get the hashcode for * @return {String} unique identifier for the given object */ toHashCode : function(obj) { if (qx.core.Environment.get("qx.debug")) { if (obj == null) { throw new Error("Invalid object: " + obj); } } var hash = obj.$$hash; if (hash != null) { return hash; } // Create new hash code var cache = this.__freeHashes; if (cache.length > 0) { hash = cache.pop(); } else { hash = (this.__nextHash++) + this.__postId; } // Store return obj.$$hash = hash; }, /** * Clears the unique identifier on the given object. * * @param obj {Object} the object to clear the hashcode for */ clearHashCode : function(obj) { if (qx.core.Environment.get("qx.debug")) { if (obj == null) { throw new Error("Invalid object: " + obj); } } var hash = obj.$$hash; if (hash != null) { this.__freeHashes.push(hash); // Delete the hash code try { delete obj.$$hash; } catch(ex) { // IE has trouble directly removing the hash // but it's ok with using removeAttribute if (obj.removeAttribute) { obj.removeAttribute("$$hash"); } } } }, /** * Get an object instance by its hash code as returned by {@link #toHashCode}. * If the object is already disposed or the hashCode is invalid, * <code>null</code> is returned. * * @param hash {String} The object's hash code. * @param suppressWarnings {Boolean?} if true warnings are suppressed; default is false * @return {qx.core.Object} The corresponding object or <code>null</code>. */ fromHashCode : function(hash, suppressWarnings) { var obj = this.__registry[hash] || null; if (!obj && !suppressWarnings) { qx.log.Logger.warn(this, "Object with hash code "+ hash + " does not exist (since Qooxdoo 6.0 fromHashCode requires that you explicitly register objects with qx.core.ObjectRegistry.register)"); } return obj; }, /** * Detects whether an object instance is indexed by its hash code as returned by {@link #toHashCode}. * Unlike {@link #fromHashCode} this does not output warnings if the object does not exist * * @param hash {String} The object's hash code. * @return {qx.core.Object} The corresponding object or <code>null</code>. */ hasHashCode : function(hash) { return !!this.__registry[hash]; }, /** * Disposing all registered object and cleaning up registry. This is * automatically executed at application shutdown. * * @deprecated {6.0} shutdown is not a valid means to clean up because destruction order * is not defined and dispose()/destructors are deprecated in favour of automatic * garbage collection */ shutdown : function() { this.inShutDown = true; var registry = this.__registry; var hashes = []; for (var hash in registry) { hashes.push(hash); } // sort the objects! Remove the objecs created at startup // as late as possible hashes.sort(function(a, b) { return parseInt(b, 10)-parseInt(a, 10); }); var obj, i=0, l=hashes.length; while(true) { try { for (; i<l; i++) { hash = hashes[i]; obj = registry[hash]; if (obj && obj.dispose) { obj.dispose(); } } } catch(ex) { qx.Bootstrap.error(this, "Could not dispose object " + obj.toString() + ": " + ex, ex); if (i !== l) { i++; continue; } } break; } qx.Bootstrap.debug(this, "Disposed " + l + " objects"); delete this.__registry; }, /** * Returns the object registry. * * @return {Object} The registry */ getRegistry : function() { return this.__registry; }, /** * Returns the next hash code that will be used * * @return {Integer} The next hash code * @internal */ getNextHash : function() { return this.__nextHash; }, /** * Returns the postfix that identifies the current iframe * * @return {Integer} The next hash code * @internal */ getPostId : function() { return this.__postId; }, /** * Returns the map of stack traces recorded when objects are registered * (for dispose profiling) * @return {Map} Map: object hash codes to stack traces * @internal */ getStackTraces : function() { return this.__stackTraces; } }, defer : function(statics) { if (window && window.top) { var frames = window.top.frames; for (var i = 0; i < frames.length; i++) { if (frames[i] === window) { statics.__postId = "-" + (i + 1); return; } } } statics.__postId = "-0"; } });