From 650969d9c5d0e4dcb1f5f1f934cb5b4ef73a69e7 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 3 Nov 2014 13:29:59 -0800 Subject: [PATCH] [Framework] Begin adding registration phase Begin implementation registration phase of framework layer initialization process. This phase is responsible for registering resolved extensions with Angular, in a manner than individual extensions can later request dependencies from. WTD-518. --- platform/framework/src/Constants.js | 1 + platform/framework/src/Extension.js | 6 ++ platform/framework/src/ExtensionRegistrar.js | 85 +++++++++++++++++++ .../framework/src/FrameworkInitializer.js | 65 ++++++++++++++ platform/framework/src/PartialConstructor.js | 46 ++++++++++ 5 files changed, 203 insertions(+) create mode 100644 platform/framework/src/ExtensionRegistrar.js create mode 100644 platform/framework/src/FrameworkInitializer.js create mode 100644 platform/framework/src/PartialConstructor.js diff --git a/platform/framework/src/Constants.js b/platform/framework/src/Constants.js index 72a4ed8618..c2d8170fd8 100644 --- a/platform/framework/src/Constants.js +++ b/platform/framework/src/Constants.js @@ -8,6 +8,7 @@ define({ BUNDLE_LISTING_FILE: "bundles.json", BUNDLE_FILE: "bundle.json", SEPARATOR: "/", + EXTENSION_SUFFIX: "[]", DEFAULT_BUNDLE: { "sources": "src", "resources": "res", diff --git a/platform/framework/src/Extension.js b/platform/framework/src/Extension.js index 9d6df56bef..eb661b3bb2 100644 --- a/platform/framework/src/Extension.js +++ b/platform/framework/src/Extension.js @@ -43,6 +43,12 @@ define( logName += " from " + bundle.getLogName(); return { + /** + * @returns {string} + */ + getKey: function () { + return definition.key || "undefined"; + }, /** * @memberof Extension# * @returns {Bundle} diff --git a/platform/framework/src/ExtensionRegistrar.js b/platform/framework/src/ExtensionRegistrar.js new file mode 100644 index 0000000000..f6e4a00067 --- /dev/null +++ b/platform/framework/src/ExtensionRegistrar.js @@ -0,0 +1,85 @@ +/*global define,Promise*/ + +/** + * Module defining ExtensionRegistrar. Created by vwoeltje on 11/3/14. + */ +define( + ['./Constants', './PartialConstructor'], + function (Constants, PartialConstructor) { + "use strict"; + + /** + * + * @constructor + */ + function ExtensionRegistrar(app, $log) { + // Track which extension categories have already been registered. + // Exceptions will be thrown if the same extension category is + // registered twice. + var registeredCategories = {}; + + function identify(category, extension, index) { + var name = extension.key ? + (extension.key + "-" + index) : + index; + return category + "[" + name + "]"; + } + + function echo() { + return arguments.slice; + } + + function staticFunction(value) { + return function () { return value; } + } + + // Utility function; create the second argument for Angular's + // .service service registration method (an array containing + // both dependencies and a factory method for the service.) + function makeServiceArgument(extension) { + var dependencies = extension.depends || [], + factory = (typeof extension === 'function') ? + new PartialConstructor(extension) : + staticFunction(extension); + + return dependencies.concat([factory]); + } + + function registerExtensionArraysForCategory(category, names) { + var name = category + Constants.EXTENSION_SUFFIX; + app.factory(name, names.concat([echo])); + } + + function registerExtensions(category, extensions) { + var names = []; + + function registerExtension(extension, index) { + var name = identify(category, extension, index); + + // Track individual extension names as-registered + names.push(name); + + app.factory(name, makeServiceArgument(extension)); + } + + if (registeredCategories[category]) { + $log.warn([ + "Tried to register extensions for category ", + category, + " more than once. Ignoring all but first set." + ].join("")); + } else { + extensions.forEach(registerExtension); + registerExtensionArraysForCategory(category, names); + registeredCategories[category] = true; + } + } + + return { + registerExtensions: registerExtensions + }; + } + + return ExtensionRegistrar; + } +); \ No newline at end of file diff --git a/platform/framework/src/FrameworkInitializer.js b/platform/framework/src/FrameworkInitializer.js new file mode 100644 index 0000000000..c54522dad5 --- /dev/null +++ b/platform/framework/src/FrameworkInitializer.js @@ -0,0 +1,65 @@ +/*global define,Promise*/ + +/** + * Module defining FrameworkInitializer. Created by vwoeltje on 11/3/14. + */ +define( + [], + function () { + "use strict"; + + /** + * + * @constructor + * @param {BundleLoader} loader + * @param {ExtensionResolver} resolver + * @param {ExtensionRegistrar} registrar + * @param {ApplicationBootstrapper} bootstrapper + */ + function FrameworkInitializer(loader, resolver, registrar, bootstrapper) { + + function registerExtensions(resolvedExtensions) { + Object.keys(resolvedExtensions).forEach(function (category) { + registrar.registerExtensions( + category, + resolvedExtensions[category] + ); + }); + } + + /** + * + * @param bundles + * @returns {Object.} an object mapping + */ + function resolveExtensions(bundles) { + var resolvedExtensions = {}; + + + function resolveExtensionsForBundle(bundle) { + + } + + return Promises.all(bundles.map(resolveExtensionsForBundle)).then(function () { + return resolvedExtensions; + }); + } + + function loadBundles(bundleList) { + return loader.loadBundles(bundleList); + } + + return { + runApplication: function (bundleList) { + return loadBundles() + .then(resolveExtensions) + .then(registerExtensions) + .then(bootstrapApplication); + } + + }; + } + + return FrameworkInitializer; + } +); \ No newline at end of file diff --git a/platform/framework/src/PartialConstructor.js b/platform/framework/src/PartialConstructor.js new file mode 100644 index 0000000000..422a51938f --- /dev/null +++ b/platform/framework/src/PartialConstructor.js @@ -0,0 +1,46 @@ +/*global define,Promise*/ + +/** + * Module defining PartialConstructor. Created by vwoeltje on 11/3/14. + */ +define( + [], + function () { + "use strict"; + + /** + * A partial constructor is used to instantiate objects in two + * stages: + * + * * First, dependencies injected from Angular + * * Second, arguments passed at run-time + * + * This allows extensions to accept both their Angular-injected + * dependencies and their per-instance attributes all in one + * constructor invocation. User code for these extensions then + * does not see the Angular dependency arguments; they may + * instantiate instances of these extensions by passing only + * those per-instance arguments. + * + * @constructor + */ + function PartialConstructor(Constructor) { + + return function () { // Bind services + var dependencies = arguments.slice(); + + return function () { // Bind everything else + var other = arguments.slice(), + instance = {}; + + Constructor.apply(instance, dependencies.concat(other)); + instance.prototype = Constructor.prototype; + + return instance; + }; + }; + } + + return PartialConstructor; + } +); \ No newline at end of file