Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Made the following changes:

1. Modified the config parser to parse invoke targets.
2. Modified the native packager to generate targets in the native packager.
3. Updated the version of the packager tools.
4. Added unit tests for invoke target.
  • Loading branch information...
commit 512f49fd21885f3efa1aad02b88229e03c1b1929 1 parent 1c1f0b2
@ronalag ronalag authored
View
79 lib/config-parser.js
@@ -243,7 +243,59 @@ function processPermissionsData(data, widgetConfig) {
});
}
+function processInvokeTargetsData(data, widgetConfig) {
+
+ if (data["rim:invokeTargets"] && data["rim:invokeTargets"]["invokeTarget"]) {
+ widgetConfig.invokeTargets = data["rim:invokeTargets"];
+ utils.wrapPropertyInArray(widgetConfig.invokeTargets, "invokeTarget");
+ widgetConfig.invokeTargets = widgetConfig.invokeTargets.invokeTarget;
+
+ widgetConfig.invokeTargets.forEach(function (invokeTarget) {
+
+ if (invokeTarget.filters) {
+ utils.wrapPropertyInArray(invokeTarget.filters, "filter");
+ invokeTarget.filters = invokeTarget.filters.filter;
+
+ invokeTarget.filters.forEach(function (filter) {
+
+ if (filter["actions"]) {
+ utils.wrapPropertyInArray(filter["actions"], "action");
+ filter["actions"] = filter["actions"]["action"];
+ }
+
+ if (filter["mime-types"]) {
+ utils.wrapPropertyInArray(filter["mime-types"], "mime-type");
+ filter["mime-types"] = filter["mime-types"]["mime-type"];
+ }
+
+ if (filter["uris"]) {
+ utils.wrapPropertyInArray(filter["uris"], "uri");
+ filter["uris"] = filter["uris"]["uri"];
+ }
+
+ if (filter["exts"]) {
+ utils.wrapPropertyInArray(filter["exts"], "ext");
+ filter["exts"] = filter["exts"]["ext"];
+ }
+ });
+ }
+
+ if (invokeTarget.permissions) {
+
+ utils.wrapPropertyInArray(invokeTarget.permissions, "permit");
+ invokeTarget.permissions = invokeTarget.permissions.permit;
+
+ //remove any empty permission elements
+ invokeTarget["permissions"].filter(function (permission) {
+ return typeof permission === "string";
+ });
+ }
+ });
+ }
+}
+
function validateConfig(widgetConfig) {
+
check(widgetConfig.version, localize.translate("EXCEPTION_INVALID_VERSION"))
.notNull()
.regex("^[0-9]{1,3}([.][0-9]{1,3}){2,3}$");
@@ -267,6 +319,32 @@ function validateConfig(widgetConfig) {
}
});
}
+
+ if (widgetConfig.invokeTargets) {
+
+ widgetConfig.invokeTargets.forEach(function (invokeTarget) {
+
+ check(typeof invokeTarget["@"] === "undefined", localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"))
+ .equals(false);
+ check(invokeTarget["@"].invokeType, localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"))
+ .isIn(["application", "viewer"]);
+ check(invokeTarget["@"].invokeId, localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"))
+ .notEmpty();
+
+ if (invokeTarget.filters) {
+
+ invokeTarget.filters.forEach(function (filter) {
+
+ check(filter["actions"], localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_INVALID"))
+ .notNull()
+ .isArray();
+ check(filter["mime-types"], localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_INVALID"))
+ .notNull()
+ .isArray();
+ });
+ }
+ });
+ }
}
function processResult(data, session) {
@@ -279,6 +357,7 @@ function processResult(data, session) {
processContentData(data, widgetConfig);
processOrientationData(data, widgetConfig);
processPermissionsData(data, widgetConfig);
+ processInvokeTargetsData(data, widgetConfig);
widgetConfig.name = data.name;
widgetConfig.description = data.description;
View
6 lib/localize.js
@@ -96,6 +96,12 @@ var Localize = require("localize"),
},
"EXCEPTION_INVALID_ACCESS_URI_NO_URN": {
"en": "Failed to parse the URI attribute in the access element($[1])"
+ },
+ "EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES": {
+ "en": "Each invokeTarget element must specify a valid invokeType and invokeId attribute"
+ },
+ "EXCEPTION_INVOKE_TARGET_FILTER_INVALID": {
+ "en": "Each filter element must specify at least one action and one type"
}
}, "", ""); // TODO maybe a bug in localize, must set default locale to "" in order get it to work
View
75 lib/native-packager.js
@@ -49,7 +49,76 @@ function generateTabletXMLFile(session, config) {
_value : 'run_native'
}
};
-
+
+ if (config.invokeTargets) {
+ xmlObject["invoke-target"] = [];
+
+ config.invokeTargets.forEach(function (invokeTarget, index) {
+
+ var xmlInvokeTarget = {
+ "_attr" : { id : invokeTarget["@"]["invokeId"] },
+ "entry-point" : config.name,
+ "type" : invokeTarget["@"]["invokeType"].toUpperCase()
+ };
+
+ if (invokeTarget.permissions) {
+ xmlInvokeTarget["require-source-capabilities"] = {
+ _value : invokeTarget.permissions.reduce(function (prev, current) {
+ return prev + "," + current;
+ })
+ };
+ }
+
+ if (invokeTarget.filters) {
+ xmlInvokeTarget.filter = [];
+
+ invokeTarget.filters.forEach(function (filter) {
+ var xmlFilter = {
+ "action" : [],
+ "mime-type": []
+ };
+
+ filter.actions.forEach(function (action) {
+ xmlFilter.action.push({
+ _value : action
+ });
+ });
+
+ filter["mime-types"].forEach(function (type) {
+ xmlFilter["mime-type"].push({
+ _value : type
+ });
+ });
+
+ if (filter.uris) {
+ xmlFilter.property = [];
+
+ filter.uris.forEach(function (uri) {
+ xmlFilter.property.push({
+ _attr: { var : "uris", value : uri }
+ });
+ });
+ }
+
+ if (filter.exts) {
+ xmlFilter.property = xmlFilter.property || [];
+
+ filter.exts.forEach(function (ext) {
+ xmlFilter.property.push({
+ _attr: { var : "exts", value : ext }
+ });
+ });
+ }
+
+ xmlInvokeTarget.filter.push(xmlFilter);
+ });
+ }
+
+ xmlObject["invoke-target"].push(xmlInvokeTarget);
+
+ });
+ }
+
//buildId
if (config.buildId) {
xmlObject.buildId = config.buildId;
@@ -62,7 +131,7 @@ function generateTabletXMLFile(session, config) {
if (file.indexOf("blackberry-tablet.xml") < 0 && !fs.statSync(file).isDirectory()) {
file = file.replace(/\\/g, "/");
file = file.split("src/")[1];
-
+
if (path.extname(file) === ".so") {
xmlObject.asset.push({
_attr : { type : 'qnx/elf' },
@@ -88,7 +157,7 @@ function generateTabletXMLFile(session, config) {
image: config.icon
};
}
-
+
//Add permissions
if (config.permissions) {
xmlObject.action = config.permissions;
View
8 lib/packager-utils.js
@@ -139,6 +139,14 @@ _self = {
return s;
},
+
+ // Wrap object property in an Array
+ wrapPropertyInArray : function (obj, property) {
+ if (obj && obj[property] && !(obj[property] instanceof Array)) {
+ obj[property] = [ obj[property] ];
+ }
+ }
+
};
module.exports = _self;
View
2  pom.xml
@@ -188,7 +188,7 @@
<artifactItem>
<groupId>net.rim.BBXwebworks</groupId>
<artifactId>packager-bin</artifactId>
- <version>1.0.0.15</version>
+ <version>1.0.0.17</version>
<type>zip</type>
<overWrite>true</overWrite>
</artifactItem>
View
59 test/config-invoke-targets.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<widget xmlns=" http://www.w3.org/ns/widgets"
+ xmlns:rim="http://www.blackberry.com/ns/widgets"
+ version="1.0.0"
+ id="My WidgetId">
+ <name>Demo</name>
+ <content src="local:///startPage.html"/>
+ <author rim:copyright="No Copyright"
+ href="http://www.rim.com/"
+ email = "author@rim.com">Research In Motion Ltd.</author>
+ <description>This app does everything.</description>
+ <license href="http://www.apache.org/licenses/LICENSE-2.0">My License</license>
+ <icon rim:hover="false" src="test.png"/>
+ <rim:permissions>
+ <rim:permit>access_shared</rim:permit>
+ <rim:permit>read_geolocation</rim:permit>
+ <rim:permit>use_camera</rim:permit>
+ </rim:permissions>
+ <rim:orientation mode="portrait" />
+ <feature id="blackberry.app" required="true" version="1.0.0.0"/>
+ <feature id="blackberry.system" required="true" version="1.0.0.3"/>
+ <access uri="http://www.somedomain1.com" subdomains="true">
+ <feature id="blackberry.app" required="true" version="1.0.0.0"/>
+ <feature id="blackberry.app.event" required="false" version="2.0.0.0"/>
+ </access>
+ <rim:invokeTargets>
+ <invokeTarget invokeType="application" invokeId="com.domain.subdomain.appname.app1">
+ <permissions>
+ <permit>access_shared</permit>
+ <permit>record_audio</permit>
+ <permit>read_geolocation</permit>
+ </permissions>
+ <filters>
+ <filter>
+ <actions>
+ <action>bb.action.OPEN</action>
+ <action>bb.action.SET</action>
+ <action>bb.action.VIEW</action>
+ </actions>
+ <mime-types>
+ <mime-type>image/*</mime-type>
+ <mime-type>text/*</mime-type>
+ </mime-types>
+ <uris>
+ <uri>ftp://</uri>
+ <uri>http://</uri>
+ <uri>https://</uri>
+ </uris>
+ <exts>
+ <ext>jpg</ext>
+ <ext>png</ext>
+ <ext>txt</ext>
+ <ext>doc</ext>
+ </exts>
+ </filter>
+ </filters>
+ </invokeTarget>
+ </rim:invokeTargets>
+</widget>
View
223 test/unit/lib/config-parser.js
@@ -444,4 +444,227 @@ describe("config parser", function () {
configParser.parse(configPath, session, {});
}).toThrow(localize.translate("EXCEPTION_INVALID_AUTHOR"));
});
+
+ it("can parse a standard invokeTargets element", function () {
+ var invokeConfigPath = path.resolve("test/config-invoke-targets.xml");
+
+ configParser.parse(invokeConfigPath, session, function (configObj) {
+ var invokeTarget = configObj.invokeTargets[0];
+
+ expect(invokeTarget).toBeDefined();
+ expect(invokeTarget["@"]).toBeDefined();
+ expect(invokeTarget["@"]["invokeType"]).toEqual("application");
+ expect(invokeTarget["@"]["invokeId"]).toEqual("com.domain.subdomain.appname.app1");
+ expect(invokeTarget.permissions).toContain("access_shared");
+ expect(invokeTarget.permissions).toContain("record_audio");
+ expect(invokeTarget.permissions).toContain("read_geolocation");
+ expect(invokeTarget.filters).toBeDefined();
+ expect(invokeTarget.filters[0].actions).toBeDefined();
+ expect(invokeTarget.filters[0].actions).toContain("bb.action.VIEW");
+ expect(invokeTarget.filters[0].actions).toContain("bb.action.SET");
+ expect(invokeTarget.filters[0].actions).toContain("bb.action.OPEN");
+ expect(invokeTarget.filters[0]["mime-types"]).toBeDefined();
+ expect(invokeTarget.filters[0]["mime-types"]).toContain("image/*");
+ expect(invokeTarget.filters[0]["mime-types"]).toContain("text/*");
+ expect(invokeTarget.filters[0].uris).toBeDefined();
+ expect(invokeTarget.filters[0].uris).toContain("ftp://");
+ expect(invokeTarget.filters[0].uris).toContain("http://");
+ expect(invokeTarget.filters[0].uris).toContain("https://");
+ expect(invokeTarget.filters[0].exts).toBeDefined();
+ expect(invokeTarget.filters[0].exts).toContain("jpg");
+ expect(invokeTarget.filters[0].exts).toContain("png");
+ expect(invokeTarget.filters[0].exts).toContain("txt");
+ expect(invokeTarget.filters[0].exts).toContain("doc");
+ });
+ });
+
+ it("can parse multiple filters in one element", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "application",
+ "invokeId": "com.domain.subdomain.appName.app"
+ },
+ "filters": {
+ "filter": [{
+ "actions": {"action": "bb.action.OPEN"},
+ "mime-types": {"mime-type": [ "text/*", "image/*" ]}
+ }, {
+ "actions": { "action": "bb.action.SET" },
+ "mime-types": {"mime-type": "image/*"}
+ }]
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).not.toThrow();
+ });
+
+ it("can parse multiple invoke targets", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": [{
+ "@": {
+ "invokeType": "application",
+ "invokeId": "com.domain.subdomain.appName.app"
+ }
+ }, {
+ "@": {
+ "invokeType": "viewer",
+ "invokeId": "com.domain.subdomain.appName.viewer"
+ }
+ }]
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).not.toThrow();
+
+ });
+
+ it("throws an error when an invoke target doesn't contain any attributes", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": [{}]
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"));
+ });
+
+ it("throws an error when an invoke target doesn't contain an invokeType attribute", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeId": "com.domain.subdomain.appName.app"
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"));
+ });
+
+ it("throws an error when an invoke target does not specify a invokeId attribute", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "application"
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"));
+ });
+
+ it("throws an error when an invoke target specifies an invalid invokeType attribute", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "myInvokeType"
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ATTRIBUTES"));
+ });
+
+ it("throws an error when a filter doesn't contain any action or mime-type elements", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "application",
+ "invokeId": "com.domain.subdomain.appName.app"
+ },
+ "filters": {
+ "filter": {
+ "uris": {"uri": "https://"},
+ "exts": {"ext": [ "html", "htm" ]}
+ }
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_INVALID"));
+ });
+
+ it("throws an error when a filter doesn't contain at least one mime-type", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "application",
+ "invokeId": "com.domain.subdomain.appName.app"
+ },
+ "filters": {
+ "filter": {
+ "actions": {"action": "bb.action.OPEN"},
+ "uris": {"uri": "https://"},
+ "exts": {"ext": [ "html", "htm" ]}
+ }
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_INVALID"));
+ });
+
+ it("throws an error when a filter doesn't contain at least one action", function () {
+ var data = testUtilities.cloneObj(testData.xml2jsConfig);
+ data["rim:invokeTargets"] = {
+ "invokeTarget": {
+ "@": {
+ "invokeType": "application",
+ "invokeId": "com.domain.subdomain.appName.app"
+ },
+ "filters": {
+ "filter": {
+ "mime-types": {"mime-type": "text/*"},
+ "uris": {"uri": "https://"},
+ "exts": {"ext": [ "html", "htm" ]}
+
+ }
+ }
+ }
+ };
+
+ mockParsing(data);
+
+ expect(function () {
+ configParser.parse(configPath, session, function (configObj) {});
+ }).toThrow(localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_INVALID"));
+ });
});
View
32 test/unit/lib/packager-utils.js
@@ -32,4 +32,34 @@ describe("Encoded Buffer data to String", function () {
var fileData = fs.readFileSync(ucs2leFile);
expect(utils.bufferToString(fileData)).toEqual(helloWorld);
});
-});
+});
+
+describe("property wrapper", function () {
+ it("wraps a property of an object in an array", function () {
+ var obj = {
+ prop: "value"
+ };
+
+ utils.wrapPropertyInArray(obj, "prop");
+ expect(obj.prop[0]).toEqual("value");
+ });
+
+ it("does not wrap an array object in an array", function () {
+ var obj = {
+ prop: ["value"]
+ };
+
+ utils.wrapPropertyInArray(obj, "prop");
+ expect(obj.prop[0][0]).not.toEqual("value");
+ expect(obj.prop[0]).toEqual("value");
+ });
+
+ it("does not wrap a property that doesn't esist in the object", function () {
+ var obj = {
+ prop: "value"
+ };
+
+ utils.wrapPropertyInArray(obj, "secondValue");
+ expect(obj.secondValue).not.toBeDefined();
+ });
+});
Please sign in to comment.
Something went wrong with that request. Please try again.