Slackyon

Overview

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" );