| function Bundle(framework, bundleData) { |
| this._framework = framework; |
| this._bundleData = bundleData; |
| this._symbolicName = null; |
| this._version = null; |
| this._imports = []; |
| this._requires = []; |
| this._exports = []; |
| this._singleton = false; |
| this._markedStarted = false; |
| this._state = INSTALLED; |
| this._scope = {}; |
| this._bundleContext = null; |
| this._activator = null; |
| |
| var headers = bundleData.getHeaders(); |
| _parseSymbolicName(headers[Constants.BUNDLE_SYMBOLICNAME]); |
| _parseVersion(headers[Constants.BUNDLE_VERSION]); |
| _parseImports(headers[Constants.IMPORT_PACKAGE]); |
| _parseExports(headers[Constants.EXPORT_PACKAGE]); |
| _parseRequires(headers[Constants.REQUIRE_BUNDLE]); |
| } |
| |
| Bundle.UNINSTALLED = 1; |
| Bundle.INSTALLED = 2; |
| Bundle.RESOLVED = 4; |
| Bundle.STARTING = 8; |
| Bundle.STOPPING = 16; |
| Bundle.ACTIVE = 32; |
| |
| Bundle.prototype = { |
| getSymbolicName : function() { |
| return this._symbolicName; |
| }, |
| getVersion : function() { |
| return this._version; |
| }, |
| getBundleId : function() { |
| return this._bundleData.getBundleId(); |
| }, |
| getLocation : function() { |
| return this._bundleData.getLocation(); |
| }, |
| getHeaders : function() { |
| return this._bundleData.getHeaders(); |
| }, |
| getState : function() { |
| return this._state; |
| }, |
| isSingleton : function() { |
| return this._singleton; |
| }, |
| isMarkedStarted : function() { |
| return this._markedStarted; |
| }, |
| equals : function(other) { |
| if (this === other) |
| return true; |
| |
| if (!other instanceof Bundle) |
| return false; |
| |
| if (this._symbolicName !== other._symbolicName) |
| return false; |
| if (this._version === null) { |
| if (other._version !== null) |
| return false; |
| } else if (!this._version.equals(other._version)) |
| return false; |
| return true; |
| }, |
| uninstall : function() { |
| this._state = Bundle.UNINSTALLED; |
| }, |
| start : function() { |
| this._markedStarted = true; |
| if (this._state !== Bundle.RESOLVED) |
| return; |
| |
| this._state = Bundle.STARTING; |
| this._bundleContext = this._framework.getBundleContext(this); |
| this._activator = this._createActivatorInstance(); |
| if (this._activator) { |
| this._activator.start(this._bundleContext); |
| } |
| this._state = Bundle.ACTIVE; |
| }, |
| stop : function() { |
| markedStarted = false; |
| if (this._state !== Bundle.ACTIVE) |
| return; |
| |
| this._state = Bundle.STOPPING; |
| if (this._activator) { |
| this._activator.stop(this._bundleContext); |
| } |
| this._state = Bundle.RESOLVED; |
| }, |
| _createActivatorInstance : function() { |
| var activatorName = this.getHeaders()[Constants.BUNDLE_ACTIVATOR]; |
| if (activatorName === null) |
| return null; |
| |
| var activatorFunction = this.lookup(activatorName); |
| if (typeof activatorFunction !== "function") |
| throw "" + activatorName + " is not a function."; |
| return new activatorFunction(); |
| }, |
| _resolve : function() { |
| if (this._state != Bundle.INSTALLED) |
| return; |
| |
| var namedExports = new Object(); // FIXME: jsdt bug for using {} with hasOwnProperty |
| var jsExport = null; |
| var i = 0; |
| // process imports (first) |
| for (i = 0; i < this._imports.length; i++) { |
| var jsImport = this._imports[i]; |
| jsExport = jsImport.getWiredExport(); |
| if (!namedExports.hasOwnProperty(jsExport.getName())) |
| namedExports[jsExport.getName()] = jsExport; |
| } |
| |
| // process requires |
| for (i = 0; i < this._requires.length; i++) { |
| var jsRequire = this._requires[i]; |
| var wiredBundle = jsRequire.getWiredBundle(); |
| var wiredBundleExports = wiredBundle.getExports(); |
| for (var j=0; j < wiredBundleExports.length; j++) { |
| jsExport = wiredBundleExports[j]; |
| if (!namedExports.hasOwnProperty(jsExport.getName())) |
| namedExports[jsExport.getName()] = jsExport; |
| } |
| } |
| |
| var names = []; |
| var exportName = null; |
| for (exportName in namedExports) { |
| if (namedExports.hasOwnProperty(exportName)) |
| names.push(exportName); |
| } |
| |
| // this sorts the set of names we'll be importing alphabetically and |
| // perhaps more importantly will allow us to create the shorter/parent dotted entries first |
| names.sort(); |
| |
| var newScope = {}; |
| for (i = 0; i < names.length; i++) { |
| exportName = names[i]; |
| jsExport = namedExports[exportName]; |
| jsExport.addToScope(newScope); |
| } |
| |
| this._evalScript(newScope); |
| this._scope = newScope; |
| this._state = Bundle.RESOLVED; |
| }, |
| _evalScript : function(scope) { |
| var scriptPath = this._bundleData.getHeaders()[Constants.BUNDLE_SCRIPTPATH]; |
| if (scriptPath === null) |
| scriptPath = Constants.BUNDLE_SCRIPT; |
| |
| var script = null; |
| var finalScript = ""; |
| var tokens = scriptPath.split(Constants.SCRIPT_PATH_DELIMITER); |
| for (var i = 0; i < tokens.length; i++) { |
| var token = tokens[i].replace(/^\s+|\s+$/g, ''); |
| if (token === Constants.SCRIPT_PATH_DOT) { |
| script = this._bundleData.getHeaders()[Constants.BUNDLE_SCRIPT]; |
| } else { |
| var scriptURI = this._bundleData.getEntry(token); |
| script = this._framework.fetch(scriptURI); |
| } |
| if (script !== null) |
| finalScript += script; |
| |
| //TODO: figure out exports |
| with(scope) { |
| eval(finalScript); |
| } |
| } |
| }, |
| _unresolve : function() { |
| if (this._state == Bundle.ACTIVE) { |
| this.stop(); |
| markedStarted = true; |
| } |
| this._scope = null; |
| |
| if (this._state == Bundle.RESOLVED) |
| this._state = Bundle.INSTALLED; |
| }, |
| _parseSymbolicName : function(header) { |
| var tokens = header.split(Constants.PARAMETER_DELIMITER); |
| this._symbolicName = tokens[0].replace(/^\s+|\s+$/g, ''); |
| for ( var i = 1; i < tokens.length; i++) { |
| var token = tokens[i]; |
| if (token.indexOf(Constants.DIRECTIVE_EQUALS) != -1) { |
| var index = token.indexOf(Constants.DIRECTIVE_EQUALS); |
| var directiveName = token.substring(0, index).replace(/^\s+|\s+$/g, ''); |
| if (directiveName.length === 0) |
| throw "bad syntax: " + token + " in " + header; |
| |
| if (directiveName !== Constants.SINGLETON_ATTRIBUTE) |
| continue; |
| var value = token.substring(index + Constants.DIRECTIVE_EQUALS.length).replace(/^\s+|\s+$/g, ''); |
| if (value.toLowerCase() === "true") |
| this._singleton = true; |
| } else |
| throw "bad syntax: " + token + " in " + header; |
| } |
| }, |
| _parseVersion : function(header) { |
| this._version = Version.parseVersion(header); |
| }, |
| _parseRequires : function(header) { |
| if (header === null) |
| return; |
| |
| var tokens = header.split(Constants.CLAUSE_DELIMITER); |
| for ( var i = 0; i < tokens.length; i++) { |
| var token = tokens[i]; |
| var jsRequire = new RequireBundle(token); |
| if (jsRequire !== null) |
| this._requires.push(jsRequire); |
| } |
| }, |
| _parseExports : function(header) { |
| if (header === null) |
| return; |
| var tokens = header.split(Constants.CLAUSE_DELIMITER); |
| for ( var i = 0; i < tokens.length; i++) { |
| var token = tokens[i]; |
| var jsExport = new ExportPackage(token, this); |
| if (jsExport !== null) |
| this._exports.push(jsExport); |
| } |
| }, |
| _parseImports : function(header) { |
| if (header === null) |
| return; |
| |
| var tokens = header.split(Constants.CLAUSE_DELIMITER); |
| for ( var i = 0; i < tokens.length; i++) { |
| var token = tokens[i]; |
| var jsImport = new ImportPackage(token); |
| if (jsImport !== null) |
| this._imports.push(jsImport); |
| } |
| }, |
| lookup : function(name) { |
| var value = this._scope; |
| if (value === null || value === undefined) { |
| return undefined; |
| } |
| var names = name.split("."); |
| for ( var i = 0; i < names.length; i++) { |
| if (value === null || value === undefined) { |
| return undefined; |
| } |
| value = value[names[i]]; |
| } |
| return value; |
| } |
| }; |