diff --git a/platform/framework/src/Bundle.js b/platform/framework/src/Bundle.js index e2ab0a719e..92c6027a92 100644 --- a/platform/framework/src/Bundle.js +++ b/platform/framework/src/Bundle.js @@ -33,6 +33,7 @@ define( function Bundle(path, bundleDefinition) { // Start with defaults var definition = Object.create(Constants.DEFAULT_BUNDLE), + logName = path, self; // Utility function for resolving paths in this bundle @@ -45,6 +46,15 @@ define( definition[k] = bundleDefinition[k]; }); + // Build up the log-friendly name for this bundle + if (definition.key || definition.name) { + logName += "("; + logName += definition.key || ""; + logName += (definition.key && definition.name) ? " " : ""; + logName += definition.name || ""; + logName += ")"; + } + return (self = { /** * @@ -88,6 +98,16 @@ define( return resolvePath(subpath); }, + /** + * Get a log-friendly name for this bundle; this will + * include both the key (machine-readable name for this + * bundle) and the name (human-readable name for this + * bundle.) + * @returns {string} log-friendly name for this bundle + */ + getLogName: function () { + return logName; + }, getExtensions: function (category) { var extensions = definition.extensions[category] || []; diff --git a/platform/framework/src/Extension.js b/platform/framework/src/Extension.js index c71904e800..9d6df56bef 100644 --- a/platform/framework/src/Extension.js +++ b/platform/framework/src/Extension.js @@ -31,7 +31,16 @@ define( * @constructor */ function Extension(bundle, category, definition) { + var logName = category; + // Build up the log-friendly name for this bundle + if (definition.key || definition.name) { + logName += "("; + logName += definition.key || ""; + logName += (definition.key && definition.name) ? " " : ""; + logName += definition.name || ""; + } + logName += " from " + bundle.getLogName(); return { /** @@ -68,6 +77,16 @@ define( bundle.getSourcePath(definition.implementation) : undefined; }, + /** + * Get a log-friendly name for this extension; this will + * include both the key (machine-readable name for this + * extension) and the name (human-readable name for this + * extension.) + * @returns {string} log-friendly name for this extension + */ + getLogName: function () { + return logName; + }, /** * @memberof Extension# * @returns {ExtensionDefinition} diff --git a/platform/framework/src/ExtensionResolver.js b/platform/framework/src/ExtensionResolver.js index 57f8dc0d2f..8572175ca0 100644 --- a/platform/framework/src/ExtensionResolver.js +++ b/platform/framework/src/ExtensionResolver.js @@ -9,12 +9,86 @@ define( "use strict"; /** + * An ExtensionResolver is responsible for loading any implementation + * modules associated with specific extensions. * + * @param {ImplementationLoader} loader used to load implementations + * @param {*} $log Angular's logging service * @constructor */ - function ExtensionResolver(require) { - return { + function ExtensionResolver(loader, $log) { + function loadImplementation(extension) { + var implPath = extension.getImplementationPath(), + implPromise = loader.load(implPath), + definition = extension.getDefinition(); + // Attach values from the object definition to the + // loaded implementation. + function attachDefinition(impl) { + var result = Object.create(impl); + + Object.keys(definition).forEach(function (k) { + result[k] = definition[k]; + }); + + // Log that this load was successful + $log.info("Loaded " + extension.getLogName()); + + return result; + } + + // Log any errors in loading the implementation, and + // return the plain extension definition instead. + function handleError(err) { + // Build up a log message from parts + var message = [ + "Could not load implementation for extension ", + extension.getLogName(), + " due to ", + err.message + ].join(""); + + // Log that the extension was not loaded + $log.warn(message); + + return extension.getDefinition(); + } + + // Log that loading has begun + $log.info([ + "Loading implementation ", + implPath, + " for extension ", + extension.getLogName() + ].join("")); + + return implPromise.then(attachDefinition, handleError); + } + + return { + /** + * Resolve the provided extension; this will give a promise + * for the extension's implementation, if one has been + * specified, or for the plain definition of the extension + * otherwise. The plain definition will also be given + * if the implementation fails to load for some reason. + * + * All key-value pairs from the extension definition + * will additionally be attached to any loaded implementation. + * + * @param {Extension} extension + */ + resolve: function (extension) { + // Log that loading has begun + $log.info([ + "Resolving extension ", + extension.getLogName() + ].join("")); + + return extension.hasImplementation() ? + loadImplementation(extension) : + Promise.resolve(extension.getDefinition()); + } }; }