|
mod-e4x is a NetKernel module that provides helper functions allowing for rapid construction of
services using the ECMAScript for XML syntax
provided in the Rhino JavaScript interpreter. With mod-e4x, JavaScript
becomes a viable alternative to the NetKernel DPML language.
When using JavaScript with NetKernel, the mod-e4x library assumes your intent is to mostly work with
XML. So, where it makes sense, all objects are converted to or wrapped as XML instances, thus removing
any need to manipulate, wrap, or un-wrap objects in NetKernel aspects. Note that reparsing rarely happens
as XMLBean and DOM instances are passed around internally.
To use the mod-e4x functions, the session.js library must be imported (see below).
The context object is provided by the NetKernel kernel. session.js provides
the session object which wraps many calls to context.
Consider this example:
context.importLibrary( "ffcpl:/includes/session.js" );
var doc = session.source( "this:param:param" ); // fetches passed param as xml
doc = doc.row[1];
session.response( doc, 1000 * 60 * 60 ); // returns the xml document and sets the cache expiry
By importing set-defaults.js, you are loading the local ffcpl:/etc/E4XConfigParameters.xml
into the config object. This sets the default cache expire time and turns logging on or off.
Any other values that need to be shared across js files can be stored here.
A more complex example:
context.importLibrary( "ffcpl:/includes/session.js" );
context.importLibrary( "ffcpl:/includes/set-defaults.js" );
var url = session.source( "this:param:param" );
var args = { "operator": "fetch-feed.js",
"param": session.byValue( url ) };
var result = session.request( "active:javascript", args );
args = { "operand": session.byReference( result ),
"type": session.byValue( "rss_1.0" ) };
result = session.request( "active:convertFeed", args );
var cache = config.fetchCacheExpiryHours * 60 * 60 * 1000;
session.response( reply, cache, config.fetchCacheCost );
With NetKernel and mod-e4x, you can quickly layer or aggregate js accessors (in this context
a js file executable by active:javascript). In the example above, fetch-feed.js
is called, which in turn calls the active:httpGet accessor in a relatively safe way (wrapped in a throttle and exception
handling), instead of just calling active:httpGet.
The possibility of continual layering and refinement allows for interatively more complex applications.
That is, by using accessors instead of functions, you can
add a global throttle (semaphore), cache the results, make async calls, etc without your
code becoming unmanageable.
Again, the intent is to allow for really rapid development of xml services. If performance is a
major concern, prototype using mod-e4x first, then stress test.
You might be surprised.
One final example:
context.importLibrary( "ffcpl:/includes/session.js" );
context.importLibrary( "ffcpl:/includes/set-defaults.js" );
function handler( error )
{
session.logWarning( error.toString() );
}
var feeds = session.source( config.feedList );
var urls = feeds.body.outline.@xmlUrl;
for each( var url in urls )
{
var args = { "operator": "fetch-normalize-feed.js",
"param": session.byReference( <url>{ url }</url> ) };
session.requestAsync( "active:javascript", args );
}
var rss = new Namespace( "rss", "http://purl.org/rss/1.0/" );
var results = session.join( handler );
var list = <ul></ul>;
for each( var item in results..rss::item )
list.* += <li><a href={item.rss::link} >{ item.rss::title.text() }</a></li>;
var html =
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Feeds</title>
</head>
<body>
<hr/>
<h4>Feeds</h4>
{ list }
<hr/>
</body>
</html>;
session.response( html, 0, 0, "text/html" );
|