Active Accessor Guide
System Development Guides
Release Notes
Developing with NetKernel
Module Development Guide
Active Accessor Guide
Data Accessor Guide
Request Guide
Universal Resource Infrastructure Design
Universal Resource Request Design
Representational Aspects
Transreptor Development Guide
Session Guide
Mod DB Guide
Compound URI Guide
License
Change History
NetKernel History
Acknowledgements

URA Development Guide - Active Accessors

Details on developing Active Accessors

Registered Active Accessors create new instructions that are accessible by languages like DPML. The system comes preconfigured with many active accessors which perform operations from simple copying of documents to evaluation of complex languages such as XQuery.

Active URAs and Instructions

The link between instructions and Active Accessors isn't obvious. As a developer of Idocs and user of accessors it isn't necessary to know. However the DPML interpretter transforms instructions into URIs. We call these URIs active URIs. They are of the form
active:{type}+{arg}@{value}+{arg}@{value}+....
where {type} is the instruction name, {arg} is, conventionally though not exclusively, one of operator, operand or param, and {value} is the URI of that part. These URIs with the active: scheme are then treated like any other URI in that they can be cached and are mapped to accessors to resolve them.

A guide to active URI's is provided here.

The best way to show what is necessary to create an active URA is to run though a simple example.

Example

As an example we will develop an accessor to convert a document's text elements to all uppercase or lowercase depending upon an optional operator document. We will map the accessor to the org.myDomain.myApp.case instruction so a DPML idoc which uses the Accessor would be:

<instr>
  <type>org.myDomain.myApp.case</type>
  <operand>var:input</operand>
  <operator>
    <case>upper</case>
  </operator>
  <target>var:output</target>
</instr>

Let us assume that we have already created a basic module in which to place the accessor. A seperate guide to creating a module is provided here.

We now follow some basic steps to create the new Active Accessor.

Step 0 - prepare classpath

An accessor must be built against the 1060netkernel.jar and any additional modules you are using the classes or resources from. The Active Accessor in this example extends XAccessor and uses classes from the layer1 and ext_xml modules. These modules should be in your classpath for building. However they should not be in your classpath for execution or debug since the Kernel always automatically discovers and installs module resources at boot time.

Step 1 - declare class

Subclass org.ten60.netkernel.xml.xahelper.XAccessor. In the constructor declare which of the instruction parts are mandatory, optional or, if no declaration is made, disallowed and whether they support fragments (xpointer references to document fragments). Standard names are OPERAND, OPERATOR and PARAMETER, though any name can be used for an argument. The second argument is true for mandatory, false for optional. The third argument is true for allowing fragments, false for not.


/*
 * CaseAccessor.java
 *
 */

package org.myDomain.myApp;

import com.ten60.netkernel.urii.*;
import org.ten60.netkernel.xml.xahelper.*;

/**
 * Case Accessor changes case of all text entries an XML document
 */
public class CaseAccessor extends XAccessor
{
    
    /** Creates a new instance of CaseAccessor */
    public CaseAccessor()
    {   declareArgument(OPERAND, true, false);
        declareArgument(OPERATOR, false, false);
    }
    
    /**source request**/
    protected IURRepresentation source(XAHelper aHelper) throws Throwable
    {
    }
    
}

Step 2 - implement method

Implement the method IURRepresentation source(org.ten60.netkernel.xml.xahelper.XAHelper aHelper) throws Throwable. This method is invoked when a request is received for this accessor from the Kernel. However the XAccessor provides a protective encapsulation layer around the kernel internals, these features include:

  • Catches any thrown java.lang.Throwable and maps it into a com.ten60.netkernel.util.NetKernelException.
  • Validates the incoming active URI against the declared arguments and handles errors.
  • Parses the incoming active URI and puts it into the XAHelper class. XAHelper provides helper utilities to obtain the resources used to invoke the URA.
  • Issues request for resources to the Kernel and manages Kernel interaction until requested resource is ready for use.
  • Provides thread safety interlock protection.
Here is the method for our example:

/**source request**/
protected IURRepresentation source(XAHelper aHelper) throws Throwable
{   Document operand = aHelper.getOperand().getReadOnlyDocument();
    Document result = (Document)XMLUtils.getInstance().safeDeepClone(operand);
    boolean toUpper=true;
    if (aHelper.hasOperator())
    {   toUpper = aHelper.getOperator().getXDA().isTrue("/case[text()='upper']");
    }
    recurse(result.getDocumentElement(),toUpper);

    IURMeta meta=aHelper.getDependencyMeta("text/xml", 8);
    DOMXDA resultXDA=new DOMXDA(result,false);

    return DOMXDAAspect.create(meta, resultXDA);
}

/*Recursively change case of text elemenets*/
private void recurse(Element e, boolean toUpper)
{   //Complete as exercise for reader
}

In this example we first retrieve the operand argument as a ReadOnly DOM. All arguments are implemented as IURRepresentations objects which are immutable since they may be referenced by many concurrent applications. Therefore to use an argument obtained from a IURRepresentation in a non-readonly fashion it must be cloned. DOM does not implement a readonly interface so we use the XMLUtils utility class to perform a safeDeepClone of the operand document.

Next XAHelper is used to see if we received an operator argument. If we have we perform an XPath evaluation to see if it specified 'upper' or 'lower' case.

The cloned result DOM is passed to the recurse() method. We'll leave it to you to think how you'd implement this.

The XAHelper creates a DependencyMeta with dependencies on each resource we have accessed and declares things such as MIME type, in this case "text/xml", and cost. This is very useful for the dependency based cache of the NetKernel.

The processed result DOM is wrapped in a DOMXDA object. DOMXDA is DOM implementation of the XDA interface - this interface provides very convenient XPath based operations, including iterators, on an underlying XML document. Finally we use a create() factory method on DOMXDAAspect to create an IURRepresentation with a DOMXDAAspect. See URII Design for more details on the object structure we are creating.

That's the Active URA completed. Next it has to be registered with it's parent module in the module.xml declaration so that it can be used.

Step 3 - register Accessor

A detailed guide to creating a module definition is provided here. Here we will show how to export our Accessor on the public interface of a module and the internal mapping required to instantiate the class for it.

The Accessor must be registered in the internal address space of the module. This is done by declaring a ura element in the mapping section.

<mapping> ...
  <ura>
    <match>active:org.myDomain.myApp.case.*</match>
    <class>org.myDomain.myApp.CaseAccessor</class>
  </ura> ...
</mapping>

The match element contains a regular expression that defines all URIs that will be processed by the accessor.

The class element contains the fully qualified name of the java class which implements the accessor.

If you want the accessor to be available publicly, that is not just for use internally within the module itself, the module definition must export the active URIs that will invoke our accessor. This is done with the following entry in the export section.

<export> ...
  <uri>
    <match>active:org.myDomain.myApp.case.*</match>
  </uri> ...
</export>

That's it. Restart NetKernel to reload the modules. Your org.myDomain.myApp.case instruction is now available for use in any idoc that imports this module.


1060® NetKernelTM Documentation
(C) 2003-2004 1060 Research Limited

Send Feedback

© 2003,2004, 1060® Research Limited
1060 registered trademark, NetKernel trademark of 1060 Research Limited