blob: 022bfb4dfc82584ae48386b782411b579b706111 [file] [log] [blame]
orion.Bundle = function(framework, bundleData) {
this._framework = framework;
this._bundleData = bundleData;
this._name = null;
this._version = null;
this._imports = [];
this._requires = [];
this._exports = [];
this._resources = {};
this._singleton = false;
this._markedStarted = false;
this._state = orion.Bundle.INSTALLED;
this._scope = {};
this._bundleContext = null;
this._activator = null;
this._script = null;
var headers = bundleData.getHeaders();
this._parseName(headers[orion.Constants.BUNDLE_NAME]);
this._parseVersion(headers[orion.Constants.BUNDLE_VERSION]);
this._parseImports(headers[orion.Constants.BUNDLE_IMPORTS]);
this._parseExports(headers[orion.Constants.BUNDLE_EXPORTS]);
this._parseRequires(headers[orion.Constants.BUNDLE_REQUIRES]);
this._parseResources(headers[orion.Constants.BUNDLE_RESOURCES]);
this._parsePath(headers[orion.Constants.BUNDLE_PATH]);
};
orion.Bundle.UNINSTALLED = 1;
orion.Bundle.INSTALLED = 2;
orion.Bundle.RESOLVED = 4;
orion.Bundle.STARTING = 8;
orion.Bundle.STOPPING = 16;
orion.Bundle.ACTIVE = 32;
orion.Bundle.prototype = {
getName : function() {
return this._name;
},
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;
},
getEntry : function(path) {
if (!path || !path instanceof String || !this._resources[path])
return null;
return this.getLocation() + path;
},
getResource : function(path) {
if (!path || !path instanceof String)
return null;
var i = 0;
var resource;
for (i = 0; i < this._imports.length; i++) {
var jsImport = this._imports[i];
var jsExport = jsImport.getWiredExport();
if (!jsExport)
continue; // optional
var name = jsExport.getName();
if (name.charAt(0) != "/")
continue; // not a resource
if (path.indexOf(name)==0) {
resource = jsExport.getExportingBundle().getEntry(path);
if (resource)
return resource;
}
}
// process requires
for (i = 0; i < this._requires.length; i++) {
var jsRequire = this._requires[i];
var wiredBundle = jsRequire.getWiredBundle();
if (!wiredBundle) {
continue; //optional
}
var wiredBundleExports = wiredBundle._getExports();
for (var j=0; j < wiredBundleExports.length; j++) {
jsExport = wiredBundleExports[j];
var name = jsExport.getName();
if (name.charAt(0) != "/")
continue; // not a resource
if (path.indexOf(name)==0) {
resource = jsExport.getExportingBundle().getEntry(path);
if (resource)
return resource;
}
}
}
return this.getEntry(path);
},
equals : function(other) {
if (this === other)
return true;
if (!other instanceof orion.Bundle)
return false;
if (this._name !== other._name)
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 = orion.Bundle.UNINSTALLED;
},
start : function() {
this._markedStarted = true;
if (this._state !== orion.Bundle.RESOLVED)
return;
this._state = orion.Bundle.STARTING;
this._bundleContext = this._framework._getBundleContext(this);
this._activator = this._createActivatorInstance();
if (this._activator) {
this._activator.start(this._bundleContext);
}
this._state = orion.Bundle.ACTIVE;
},
stop : function() {
markedStarted = false;
if (this._state !== orion.Bundle.ACTIVE)
return;
this._state = orion.Bundle.STOPPING;
if (this._activator) {
this._activator.stop(this._bundleContext);
}
this._state = orion.Bundle.RESOLVED;
},
load : 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;
},
_isSingleton : function() {
return this._singleton;
},
_isMarkedStarted : function() {
return this._markedStarted;
},
_getImports : function() {
return this._imports;
},
_getExports : function() {
return this._exports;
},
_getRequires : function() {
return this._requires;
},
_createActivatorInstance : function() {
var activatorName = this.getHeaders()[orion.Constants.BUNDLE_ACTIVATOR];
if (activatorName === null || activatorName === undefined)
return null;
var activatorFunction = this.load(activatorName);
if (typeof activatorFunction !== "function")
throw "" + activatorName + " is not a function.";
return new activatorFunction();
},
_resolve : function() {
if (this._state != orion.Bundle.INSTALLED)
return;
var namedExports = {};
var jsExport = null;
var i = 0;
// process imports (first)
for (i = 0; i < this._imports.length; i++) {
var jsImport = this._imports[i];
var jsExport = jsImport.getWiredExport();
if (!jsExport)
continue; // optional
var name = jsExport.getName();
if (name.charAt(0) == "/")
continue; // resource
if (!namedExports.hasOwnProperty(name))
namedExports[name] = jsImport.getWiredExport();
}
// process requires
for (i = 0; i < this._requires.length; i++) {
var jsRequire = this._requires[i];
var wiredBundle = jsRequire.getWiredBundle();
if (!wiredBundle) {
continue; //optional
}
var wiredBundleExports = wiredBundle._getExports();
for (var j=0; j < wiredBundleExports.length; j++) {
jsExport = wiredBundleExports[j];
var name = jsExport.getName();
if (name.charAt(0) == "/")
continue; // resource
if (!namedExports.hasOwnProperty(name))
namedExports[name] = jsImport.getWiredExport();
}
}
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 importScope = {};
for (i = 0; i < names.length; i++) {
exportName = names[i];
jsExport = namedExports[exportName];
jsExport.addToScope(importScope);
}
this._evalScript(importScope);
this._state = orion.Bundle.RESOLVED;
},
_evalScript : function(importScope) {
var parameterNames = [];
var parameterValues = [];
var parameterName = null;
for (parameterName in importScope) {
if (importScope.hasOwnProperty(parameterName)) {
parameterNames.push(parameterName);
parameterValues.push(importScope[parameterName]);
}
}
var exportNames = [];
for (i = 0; i < this._exports.length; i++) {
var exportName = this._exports[i].getName();
if (exportName.charAt(0) == "/")
continue; // resource
var dotIndex = exportName.indexOf(".");
if (dotIndex !== -1)
exportName = exportName.substring(0,dotIndex);
if (! exportNames.hasOwnProperty(exportName)) {
exportNames[exportName] = true;
exportNames.push(exportName + ":" + exportName);
}
}
var parameterStatement = parameterNames.join(",");
var returnStatement = "\n\nreturn {" + exportNames.join(",") + "};";
var finalScript = this._script + returnStatement;
var load = new Function(parameterStatement, finalScript);
var that = this;
var _ResourceWrapper = function() {
this.getResources = function(path) {
return that.getResources(path);
};
};
_ResourceWrapper.prototype = orion.global;
var context = new _ResourceWrapper();
this._scope = load.apply(context, parameterValues);
},
_unresolve : function() {
if (this._state == orion.Bundle.ACTIVE) {
this.stop();
markedStarted = true;
}
this._scope = null;
if (this._state == orion.Bundle.RESOLVED)
this._state = orion.Bundle.INSTALLED;
},
_parseName : function(header) {
var tokens = header.split(orion.Constants.PARAMETER_DELIMITER);
this._name = tokens[0].replace(/^\s+|\s+$/g, '');
for ( var i = 1; i < tokens.length; i++) {
var token = tokens[i];
if (token.indexOf(orion.Constants.DIRECTIVE_EQUALS) != -1) {
var index = token.indexOf(orion.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 !== orion.Constants.SINGLETON_DIRECTIVE)
continue;
var value = token.substring(index + orion.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 = orion.Version.parseVersion(header);
},
_parseResources : function(header) {
if (!header)
return;
var tokens = header.split(orion.Constants.CLAUSE_DELIMITER);
for ( var i = 0; i < tokens.length; i++) {
if (tokens[i]) {
var path = tokens[i].replace(/^\s+|\s+$/g, '');
this._resources[path] = true;
}
}
},
_parseRequires : function(header) {
if (!header)
return;
var tokens = header.split(orion.Constants.CLAUSE_DELIMITER);
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var jsRequire = new orion.Require(token);
if (jsRequire !== null)
this._requires.push(jsRequire);
}
},
_parseExports : function(header) {
if (!header)
return;
var tokens = header.split(orion.Constants.CLAUSE_DELIMITER);
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var jsExport = new orion.Export(token, this);
if (jsExport !== null)
this._exports.push(jsExport);
}
},
_parseImports : function(header) {
if (!header)
return;
var tokens = header.split(orion.Constants.CLAUSE_DELIMITER);
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var jsImport = new orion.Import(token);
if (jsImport !== null)
this._imports.push(jsImport);
}
},
_parsePath : function(header) {
if (!header) {
this._script = this._bundleData.getHeaders()[orion.Constants.BUNDLE_SCRIPT] || "";
return;
}
var tokens = header.split(orion.Constants.CLAUSE_DELIMITER);
var scripts = [];
for ( var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var path = token.replace(/^\s+|\s+$/g, '');
if (path === ".") {
scripts[i] = this._bundleData.getHeaders()[orion.Constants.BUNDLE_SCRIPT];
} else {
var scriptURL = this.getResource(path);
scripts[i] = orion.Framework._fetch(scriptURL);
}
}
this._script = scripts.join("\n\n");
}
};