OpenAjax Device APIs
From MemberWiki
Contents
|
LATEST PROPOSAL
Here are some newer ideas that for how the shim layer might work. Consider this as something that proposes a general direction rather than a detailed proposal.
How an application would load the shim layer
Let's assume an Ajax application that wants to access features on a particular device (e.g., the address book). The following are some examples that show how the shim layer open source and one particular provider might get loaded.
Load example 1
This example assumes that the server has determined which mobile device is being used and dynamically inserted line [6] below based on the device, such as analyzing the HTTP_USER_AGENT HTTP header. (Note: if the adapter uses a browser plugin and that browser plugin requires an <embed> or <object> tag to get loaded, it is the responsibility to the adapter JavaScript to insert the appropriate <embed> or <object> tag into the DOM.)
[1] <html> [2] <head> [3] <!-- Load the shim layer JavaScript --> [4] <script type="text/javascript" src="OpenAjaxDevice.js"/> [5] <!-- Load a provider that maps the shim layer to platform-specific APIs. --> [6] <script type="text/javascript" src="XYZAdapter.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] ... [12] </body> [13] </html>
Load example 2
A variation on the above moves all of the user agent analysis from the server to the client. In this example, we assume that someone in the industry has written some client-side JavaScript/Ajax library (ABCLibrary.js) that determines which platform and browser is being used, and which plugins/extensions might be available. This JavaScript library then downloads the appropriate provider(s) dynamically from a server, probably using a dynamically inserted SCRIPT tag.
[1] <html> [2] <head> [3] <!-- Load the shim layer JavaScript --> [4] <script type="text/javascript" src="OpenAjaxDevice.js"/> [5] <!-- Load a JavaScript library that pulls down any providers that might be needed. --> [6] <script type="text/javascript" src="ABCLibrary.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] ... [12] </body> [13] </html>
Load example 3
We will encourage other Ajax libraries to bundle our shim layer as part of their distribution. (Just like what we did with OpenAjax Hub: see [1].)
In the example below, it is assumed that the shim layer is bundled with XYZLibrary.js.
[1] <html> [2] <head> [3] <!-- No need to load OpenAjaxDevice.js - it is bundled in DEFLibrary.js - --> [4] [5] <!-- Load a JavaScript library that bundles OpenAjaxDevice.js and pulls downs providers. --> [6] <script type="text/javascript" src="XYZLibrary.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] ... [12] </body> [13] </html>
How a provider would hook into the shim layer
Here is a proposal for how a given provider would register itself with the OpenAjaxDevice.js shim layer.
Let's assume there is an XYZAdapter.js that plugs into the shim layer and converts all of the OpenAjax.device.pim.addressBook.* API calls into appropriate platform-specific calls for the XYZ platform.
MyAddressBookFunctions = {
getAddressBook: function(...) { ... };
...
};
OpenAjax.device.providers.register("XYZAdapter","pim.addressBook",MyAddressBookFunctions,ReadyCallback,ErrorCallback);
The ReadyCallback is a callback function that is invoked once the provider is ready for use. The ReadyCallback is a callback function that is invoked if something goes wrong with the registration and initialization.
(Note: probably the above API isn't what we would go will ultimately, but it illustrates the essential concepts.)
Last provider wins
The rule is that the last provider to register wins. If ABCAdapter registers "pim.addressBook" and subsequently XYZAdapter also registers "pim.addressBook", then when the addressBook APIs are invoked, the XYZAdapter would be used.
Provider maps from OpenAjax-style APIs into actual platform APIs
The parameter list passed to the provider matches the parameter list defined for the OpenAjax APIs. For example, if there is a send email API such as OpenAjax.device.email.sendMail(to,from,cc,messagebody), then the shim layer would invoke the provider with the same parameters (i.e., to,from,cc,messagebody). The provider would then have the responsibility of mapping the functions and parameters into whatever lower-level capabilities exist on the target platform.
How user JavaScript invokes the OpenAjax Device APIs
Here is an example:
function MyCallBack(...) { ... }
OpenAjax.device.pim.getAddressBook(...,MyCallBack,...);
Shim layer under the hood
The shim layer might be end up being very small. The key logic would be a lookup into an associative array, followed by a JavaScript apply. Here is how the shim layer source code might look:
OpenAjax.device.providers.register = function(
adapterName, moduleName, funclist, ReadyCallBack, ErrorCallback)
{
// FIXME: Need to add checking and error handling logic
var module_array = moduleName.split('.');
var nlevels = module_array.length;
var obj = OpenAjax.device;
for (var i = 0; i < nlevels; i++) {
obj = obj[module_array[i]];
}
obj.funcs = funclist;
// Invoke ReadyCallBack().
}
OpenAjax.device.pim.addressBook.getAddressBook = function() {
//FIXME: Not sure this JavaScript is correct.
// FIXME: Need to add checking and error handling logic
this.funcs.getAddressBook.apply(arguments);
}
OLDER PROPOSAL
Here are some ideas that for how the shim layer might work. These are just early strawmen before actually writing code, so consider this as something that proposes a general direction rather than a detailed proposal.
How an application would load the shim layer
Let's assume an Ajax application that wants to access features on a particular device (e.g., the address book). The following are some examples that show how the shim layer open source and one particular provider might get loaded.
Load example 1
This example assumes that the server has determined which mobile device is being used and dynamically inserted line [6] below based on the device, such as analyzing the HTTP_USER_AGENT HTTP header. Depending on the situation, the server might also have to dynamically insert an OBJECT tag (see line [11] that causes a browser plugin to be activated.
[1] <html> [2] <head> [3] <!-- Load the shim layer JavaScript --> [4] <script type="text/javascript" src="OpenAjaxDevice.js"/> [5] <!-- Load a provider that maps the shim layer to platform-specific APIs. --> [6] <script type="text/javascript" src="XYZAdapter.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] <object .../> [12] ... [13] </body> [14] </html>
Load example 2
A variation on the above moves all of the user agent analysis from the server to the client. In this example, we assume that someone in the industry has written some client-side JavaScript/Ajax library (ABCLibrary.js) that determines which platform and browser is being used, and which plugins/extensions might be available. This JavaScript library then downloads the appropriate provider(s) dynamically from a server, probably using a dynamically inserted SCRIPT tag.
[1] <html> [2] <head> [3] <!-- Load the shim layer JavaScript --> [4] <script type="text/javascript" src="OpenAjaxDevice.js"/> [5] <!-- Load a JavaScript library that pulls down any providers that might be needed. --> [6] <script type="text/javascript" src="ABCLibrary.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] <object .../> [12] ... [13] </body> [14] </html>
Load example 3
We will encourage other Ajax libraries to bundle our shim layer as part of their distribution. (Just like what we did with OpenAjax Hub: see [2].)
In the example below, it is assumed that the shim layer is bundled with XYZLibrary.js.
[1] <html> [2] <head> [3] <!-- No need to load OpenAjaxDevice.js - it is bundled in DEFLibrary.js - --> [4] [5] <!-- Load a JavaScript library that bundles OpenAjaxDevice.js and pulls downs providers. --> [6] <script type="text/javascript" src="DEFLibrary.js"/> [7] <!-- Load my application-specific JavaScript. This logic invokes OpenAjax.device.*. --> [8] <script type="text/javascript" src="MyApplicationLogic.js"/> [9] </head> [10] <body> [11] <object .../> [12] ... [13] </body> [14] </html>
How a provider would hook into the shim layer
Here is a proposal for how a given provider would register itself with the OpenAjaxDevice.js shim layer.
Let's assume there is an XYZAdapter.js that plugs into the shim layer and converts all of the OpenAjax.device.* API calls into appropriate platform-specific calls for the XYZ platform.
MyFunctions = {
geo: {
getCurrentLocation: function(...) { ... };
},
pim: {
getAddressBook: function(...) { ... };
},
...
};
OpenAjax.device.providers.register("XYZAdapter",MyFunctions);
How user JavaScript invokes the OpenAjax Device APIs
An application would need to get a "connection handle" for each of the adapters that have been loaded, and then invoke the OpenAjax device APIs through that connection handle. We could support two alternative APIs for
Method 1: Invoking OpenAjax.device.whatever() APIs
With Method 1, applications can invoke the OpenAjax.device.... APIs, but the first parameter would be the connection handle:
ConnHandle = OpenAjax.device.connect("XYZAdapter");
...
contacts = OpenAjax.device.pim.getAddressBook(ConnHandle,...);
Method 2: Invoking APIs through the connection handle
With Method 2, applications can invoke the APIs through the connection handle:
ConnHandle = OpenAjax.device.connect("XYZAdapter");
...
contacts = ConnHandle.pim.getAddressBook(...);
Shim layer under the hood
The shim layer might be end up being very small. The key logic would be a lookup into an associative array, followed by a JavaScript apply. Here is how the shim layer source code might look:
OpenAjax.device = {
pim: {
getAddressBook: function(ConnHandle,...) {
// Shown inline here, but almost certainly this logic would be in a common utility function.
var f = ConnHandle.fcts["getAddressBook"];
if (f) {
newargs = arguments.shift();
f.apply(this,newargs);
}
// etc. for all of the other PIM APIs
},
// etc. for all of the other APIs
};
