# DirXML™ Driver Frequently-Asked-Questions (FAQ)

## Contents

What is a driver?
How does a driver fit into the DirXML framework?
What are the responsibilities of a driver?
Does a driver need to know anything about rules?
What is an association?
How does DirXML communicate with the driver?
What are these interfaces?

Implemented by driver
Implemented by DirXML

How are these interfaces used?
What is the XmlDocument used by the interfaces?
How do I create a DOM document?
What is the structure of the XML documents passed to and from the various interface methods?

Example

What is the difference between events and commands?
What are rules?
What is rule chaining?
What does the Schema Mapping Rule do?
What does the Input Transformation Rule do?
What does the Output Transformation Rule do?
What does the Event Transformation Rule do?
What does the Command Transformation Rule do?
What does the Matching Rule do?
What does the Create Rule do?
What does the Placement Rule do?
What does an Event Filter do?
What is the general flow of an event through the Event Filter and rules?

Subscriber Channel
Publisher Channel

How do the Event Filter and the rules interact with each other?
What do I need to know to implement a rule using an XSLT stylesheet?

Understand XSLT and the XML you will be transforming
Understand the goal of the rule you are implementing
Start out with the identity transformation
Use the parameters that are passed into the stylesheet
Use extension functions as needed

How do I invoke the Novell XSLT processor directly?
Are there any other utility classes available to make my job easier?
Does my driver have to do anything special to work with the DirXML Remote Loader?
How can I debug my driver or rules?

Use DSTRACE.
Attach a Java debugger (This is currently only supported on Win32).
Environment Variables

## What is a driver?

A driver is the piece of code that allows DirXML to communicate with an external application in order to synchronize data between that application and NDS.

## How does a driver fit into the DirXML framework?

DirXML can be thought of as two separate black boxes called channels. Each channel takes an event on its input and issues a set of commands on its output. The goal of the transformation from events to commands is to propagate the changes made by the application connected to the channel input into the application connected to the channel output. The transformation involves fixed logic in DirXML together with a set of configurable rules that guide the transformation of events to commands.

The first channel is the Subscriber channel. NDS acts as the Subscriber channel input and a driver's SubscriptionShim acts as the Subscriber channel output. The Subscriber channel therefore accepts NDS events, generates commands with the help of the rules, and issues those commands to the SubscriptionShim which then updates the application.

The second channel is the Publisher channel. The driver's PublicationShim acts as the Publisher channel input and NDS acts as the Publisher channel output. The Publisher channel therefore accepts events for the application through the PublicationShim, generates commands with the help of the rules, and issues those commands to update NDS.

## What are the responsibilities of a driver?

- A driver does only what DirXML tells it to do. (SubscriptionShim).
- A driver reports to DirXML any relevant events that occur in the application. (PublicationShim).

## Does a driver need to know anything about rules?

No. It is useful for the driver writer to understand what rules do, but the driver has no responsibility for rules processing. The driver writer should have a good understanding of the responsibilities of the driver before worrying about the rules.

## What is an association?

Associations are the mechanism used by DirXML to establish and maintain a correspondence between an object in NDS and an application object. The driver provides a unique key value for each application object, and DirXML manages the storage of those key values in NDS.

A driver's responsibility with respect to associations is to provide a unique key value for each object and to notify DirXML whenever something happens that affects that unique key. In practice this means:

- Provide the unique key value for the object whenever communicating any information about the object to DirXML (events and queries).
- Report to DirXML whenever the unique key value of a relevant object changes using <modify-association>.
- Report to DirXML the unique key value of an object created as a result of processing <add> in the SubscriptionShim using <add> in the result document returned from the add processing.
- Optionally tell DirXML to forget any key that is no longer valid and for which driver has reason to believe that DirXML is still holding using <remove-association>. The most common occurrence of this is when DirXML sends a command using a key value that no longer exists in the application.

## How does DirXML communicate with the driver?

DirXML communicates with a driver through interfaces. In Java these are represented by Java interfaces. In C++ these are represented as pure abstract base classes. In the interest of brevity this document will focus primarily on the Java interfaces. A FAQ on C++ drivers is available and covers items specifically of interest to writers of C++ drivers.

## What are these interfaces?

### Implemented by driver

- DriverShim - The top-level interface responsible for starting up and shutting down the driver.
- SubscriptionShim - The interface responsible for accepting and processing commands from DirXML.
- PublicationShim - The interface responsible for notifying DirXML of events that occur in the application.
- XmlQueryProcessor - The interface passed by the PublicationShim into XmlCommandProcessor.execute() when calling DirXML to report an application event. DirXML uses the XmlQueryProcessor interface to query the PublicationShim for any additional information DirXML may need to process the application event.

### Implemented by DirXML

- XmlCommandProcessor - The interface passed to PublicationShim.start() so that the PublicationShim can notify DirXML of application events.
- XmlQueryProcessor - The interface passed by DirXML to SubscriptionShim.execute() so that the SubscriptionShim can query DirXML for any additional information it may need to process a command.

## How are these interfaces used?

1. DriverShim is instantiated by DirXML via introspection using a no-argument constructor.
2. DriverShim.init() method is called by DirXML. DirXML passes in the driver initialization parameters.
3. DirXML retrieves the object implementing the SubscriptionShim interface using DriverShim.getSubscriptionShim().
4. DirXML retrieves the object implementing the PublicationShim interface using DriverShim.getPublicationShim().
5. DirXML calls SubscriptionShim.init(), passing the Subscriber initialization parameters.
6. A separate Publisher thread is created. In the Publisher thread:
   1. DirXML calls PublicationShim.init(), passing the Publisher initialization parameters.
   2. DirXML calls PublicationShim.start(), passing the DirXML object that implements XmlCommandProcessor. The PublicationShim.start() method loops, notifying DirXML using XmlCommandProcessor.execute() whenever a relevant event occurs in the application. It does not return until DriverShim.shutdown() is called unless there is a fatal error.
      - XmlCommandProcessor.execute() processes the event, possibly calling the driver XmlQueryProcessor (passed into XmlCommandProcessor.execute()) one or more times if additional information is needed by DirXML to process the event.
7. DirXML monitors NDS for relevant events and invokes SubscriptionShim.execute() when an application object must be created or a change must be made to an application object. In addition, DirXML invokes SubscriptionShim.execute() to query the application for information about application objects.
   - SubscriptionShim.execute() processes the command, optionally calling the DirXML XmlQueryProcessor (passed into SubscriptionShim.execute()) one or more times if additional information is needed to process the command.
8. At some time in the future NDS sends DirXML an event telling DirXML to shut down the driver. DriverShim.shutdown() is called, which performs whatever driver-specific cleanup is needed (including signaling the PublicationShim to return from start().)

## What is the XmlDocument used by the interfaces?

XmlDocument is a high level abstraction representing an XML document. It allows for easy conversions between several common representations of XML, notably Document Object Model (DOM), Simple API for XML 1.0 (SAX), and a serialized, human-readable form. This allows drivers to create and consume XML documents in the form that is most convenient for the particular application. DirXML predominantly uses DOM internally, but uses the serialized form when logging messages to DSTRACE. Most drivers will probably also use DOM internally, but drivers which must pass the XML to external or remote processes will likely use the serialized form as well.

## How do I create a DOM document?

The implementation of DOM used by DirXML is provided by nxsl.jar (which contains Novell's XSLT processor as well as many XML utility classes). To create a document that uses the same implementation as DirXML, use com.novell.xml.dom.DocumentFactory.newDocument().

It is possible for a driver to use a different implementation of DOM. However, keep in mind that documents that are passed to the driver by DirXML will always use the nxsl.jar implementation, so any extensions to DOM that might be available in another implementation will not be available in documents received from DirXML. Note also that the performance of the Novell XSLT processor is significantly better on documents created using the nxsl.jar implementation.

## What is the structure of the XML documents passed to and from the various interface methods?

The documents passed to and from the various methods have a structure defined by nds.dtd. All documents use <nds> as the document (top-level) element, which may contain an optional <source> element. Documents that are passed as parameters to interface methods also contain a single <input> element that contains an arbitrary number of events or commands as applicable. Documents that are returned from interface methods contain a single <output> element which contains the results of the processing the events or commands contained in the input document and may contain a limited set of commands.

### Example

DirXML sends:

    <nds dtdversion="1.0" ndsversion="8.5">
       <source>
          <product asn1id="2 16 840 1 113719 1 x" version="1.0b3">DirXML</product>
          <contact>Novell, Inc.</contact>
       </source>
       <input>
          <!-- input commands or events go here -->
       </input>
    </nds>

Shim returns:

    <nds dtdversion="1.0" ndsversion="8.5">
       <source>
          <product version="1.0b3">Some Application Driver</product>
          <contact>Nobody in particular</contact>
       </source>
       <output>
          <!-- results from commands or events go here -->
       </output>
    </nds>

## What is the difference between events and commands?

The distinction is subtle but important. Many of the possible child elements of <input> can be interpreted either as commands or as events, depending on the context, and have essentially the same syntax. In general, for elements that can be used as either a command or as notification of an event the following applies: If the element is being sent to the driver the element is a command and if the element is being sent to DirXML the element is an event notification. When the driver sends an event notification to DirXML the driver is informing DirXML of something that occurred in the application. DirXML will then determine, based on configurable rules, what commands, if any, must be sent to NDS. When DirXML sends a command to the driver, DirXML has already taken an NDS event as input, applied the appropriate rules, and determined that the change in the application represented by the command is necessary.

## What are rules?

Rules help DirXML transform an event on a channel input into a set of commands on the channel output. Rules are configurable by the System Administrator so that the rules can be customized to do whatever an individual installation requires. Some rules perform a well-defined role in the event-to-command transformation while others allow for more general customization. All rules can be implemented using XSLT stylesheets, but rules that perform well-defined roles more commonly use a DirXML-specific XML format (a "simple" rule) that more easily describes the transformation needed. Rules that use DirXML-specific XML formats can usually be created and edited using ConsoleOne snapins that guide the administrator in creating the rules so that the administrator does not have to see the raw XML that encodes the rule. However, when an XSLT stylesheet is used as a rule (either for those rules that can only be implemented using XSLT or as a replacement for one of the more common rules) the XSLT must be programmed manually.

Rules are stored in the XmlData attribute of DirXML-Rule and DirXML-Stylesheet objects. The DirXML-Driver, DirXML-Subscriber, and DirXML-Publisher objects have attributes that reference the rule objects:

- DirXML-Driver
  - DirXML-MappingRule
  - DirXML-InputTransform
  - DirXML-OutputTransform
- DirXML-Subscriber and DirXML-Publisher
  - DirXML-EventTransformationRule
  - DirXML-MatchingRule
  - DirXML-CreateRule
  - DirXML-PlacementRule
  - DirXML-CommandTransformationRule
- DirXML-Publisher
  - DirXML-EventTransformationRule
  - DirXML-MatchingRule
  - DirXML-CreateRule
  - DirXML-PlacementRule
  - DirXML-CommandTransformationRule

## What is rule chaining?

Rule chaining is a feature added in DirXML 1.1 that allows multiple rule objects to be chained together to form the total rule processing for a rule step (e.g., Create Rule, Placement Rule, etc.). This allows a stylesheet to supplement the operation of a simple rule without having to completely replace the rule with a stylesheet.

Rules are chained together using the DirXML-NextTransformation attribute on the rule object. Any number of rules may be chained; multiple simple rules and stylesheets may be freely mixed. There may not be any loops in the chain, and any simple rules used must match the rule step. In other words, if rules are being chained in the Create Rule step, any simple rules must use the simple Create Rule syntax.

## What does the Schema Mapping Rule do?

The Schema Mapping Rule is referenced by the driver object and applies to both the Subscriber channel and to the Publisher channel. The purpose of the Schema Mapping Rule is to map schema names (particularly attribute names and class names) between the NDS namespace and the application namespace. The rule syntax is defined by the documentation for <attribute-name-map>. The Schema Mapping Rule is applied to the XML documents sent to and returned from SubscriptionShim.execute(), XmlQueryProcessor.query(), and XmlCommandProcessor().execute(). The Schema Mapping Rule is also applied to XML sent to (but not to XML returned from) SubscriptionShim.init() and PublicationShim().init(). The Schema Mapping Rule is applied before the Output Transformation Rule when DirXML issues a document to the driver and before the Input Transformation Rule when the driver issues a document to DirXML.

## What does the Input Transformation Rule do?

The Input Transformation Rule is referenced by the driver object and applies to both the Subscriber channel and to the Publisher channel. The purpose of the Input Transformation Rule is to perform any preliminary transformation on all XML documents sent to DirXML by the driver and returned to DirXML from the driver. The Input Transformation Rule is applied to the XML document sent to XmlCommandProcessor.execute() and XmlQueryProcessor.query() (when called by the driver) and to the XML document returned from SubscriptionShim.execute(), and XmlQueryProcessor.query() (when called by DirXML). The Input Transformation Rule is applied before the Schema Mapping Rule.

The Input Transformation Rule is always implemented using an XSLT stylesheet. A common application is performing data format mapping. Note that schema names will always be in the application namespace in the XML processed by the Input Transformation Rule.

It is possible to use the Input Transformation Rule to transform an arbitrary XML format native to the target application to the format expected by DirXML, but this is discouraged because it makes it harder for administrators to customize the rule for site-specific needs. It is usually wiser if the driver performs this transformation itself, possibly by calling the Novell XSLT processor directly.

## What does the Output Transformation Rule do?

The Output Transformation Rule is referenced by the driver object and applies to both the Subscriber channel and to the Publisher channel. The purpose of the Output Transformation Rule is to perform any final transformation necessary on the XML documents sent to the driver by DirXML and returned to the driver by DirXML. The Output Transformation Rule is applied to the XML document sent to SubscriptionShim.execute() and XmlQueryProcessor.query() (when called by DirXML) and to XML returned from XmlCommandProcessor.execute() and XmlQueryProcessor.query() (when called by the driver). The Output Transformation Rule is applied after the Schema Mapping Rule.

The output transform is always implemented using an XSLT stylesheet. A common application is performing data format mapping. Note that schema names will always be in the application namespace in the XML processed by the Output Transformation Rule.

It is possible to use the Output Transformation Rule to transform between DirXML format and an arbitrary XML format native to the target application, but this is discouraged because it makes it harder for administrators to customize the rule for site-specific needs. It is usually wiser if driver performs this transformation itself, possibly by calling the Novell XSLT processor directly.

## What does the Event Transformation Rule do?

An Event Transformation Rule may be referenced by the Subscriber object and/or by the Publisher object (typically the Subscriber and Publisher would reference different rule objects). The purpose of an Event Transformation Rule is to perform preliminary transformations on events. When referenced by the Subscriber object the Event Transformation Rule applies to events received by DirXML from NDS and is applied before any other event processing. When referenced by the Publisher object the Event Transformation Rule applies to events issued by the driver to DirXML and is applied after the Input Transformation Rule and Schema Mapping Rules, but before any other event processing.

The Event Transformation Rule is always implemented using an XSLT stylesheet. There are many common applications for the Event Transformation Rule, including:

- custom event filtering
- transforming the event directly into a custom command to be passed to the application
- generating additional events

## What does the Command Transformation Rule do?

A Command Transformation Rule may be referenced by the Subscriber object and/or by the Publisher object (typically the Subscriber and Publisher would reference different rule objects). The purpose of the Command Transformation Rule is to provide final processing on commands before the commands are sent to eDirectory or the application. Note that the Command Transformation Rule did not exist in DirXML 1.0; the Command Transformation Rule was added in DirXML 1.1.

The Command Transformation Rule on the Publisher channel is executed after all other rules and is executed directly before the DirXML engine applies the commands in the command document to eDirectory. It is the "last chance" to modify a command before the command is applied to eDirectory.

The Command Transformation Rule on the Subscriber channel is executed directly before the Schema Mapping Rule. Both the Schema Mapping Rule and the Output Transformation are executed after the Command Transformation Rule on the Subscriber channel.

The Command Transformation Rule is always implemented using an XSLT stylesheet. Many applications that had to be performed in the Event Transformation Rule in DirXML 1.0 can be more easily performed in the Command Transformation Rule in DirXML 1.1. This is because all event to command processing performed by the DirMXL Engine has already been performed.

Some other possible applications for the Command Transformation Rule include:

- changing the command type (for example, an object delete command might be transformed into a modification that will cause the object to be archived)
- generating additional events
- blocking commands
- adding additional commands
- controlling the output of the DirXML Engine's "merge" process

## What does the Matching Rule do?

A Matching Rule may be referenced by the Subscriber object and/or by the Publisher object (typically the Subscriber and Publisher would reference different rule objects). The purpose of the Matching Rule is to automatically associate objects in NDS with objects in the application. The rule syntax is defined by the documentation for <matching-rules>. The matching rule is only applied to <add> events.

## What does the Create Rule do?

A Create Rule may be referenced by the Subscriber object and/or by the Publisher object (typically the Subscriber and Publisher would reference different rule objects). The purpose of the Create Rule is to decide whether or not to create a new object if a suitable association could not be automatically generated by the Matching Rule. A Create Rule also can perform other modifications to the <add> event such as providing default values for attributes and/or specifying an object to use as a template for creating the new object. The rule syntax is defined by the documentation for <create-rules>. The Create Rule is only applied to <add> events for which no matches for the corresponding object were found by the Matching Rule.

## What does the Placement Rule do?

A Placement Rule may be referenced by the Subscriber object and/or by the Publisher object (typically the Subscriber and Publisher would reference different rule objects). The purpose of the Placement Rule is to determine where in the storage hierarchy to place an object that is to be created and to determine the name for the new object. For NDS and other directory applications this means generating a distinguished name for the new object. The rule syntax is defined by the documentation for <placement-rules>. The Placement Rule is only applied to <add> events which were not vetoed by the Create Rule.

## What does an Event Filter do?

An Event Filter specifies the classes of objects and the attributes of those objects for which DirXML will process events. Separate Event Filters are specified for the Subscriber and Publisher channels. Event Filters only pass events on objects whose effective class matches one of those classes specified by the filter. Event Filters do not pass events on objects that are a subclass of a class specified in the filter unless the subclass is also specified.

## What is the general flow of an event through the Event Filter and rules?

The following is the general order of rule processing. Note that this is an extreme over-simplification of the processing that actually occurs and that processing may stop at any point or skip to the last step if the result of processing a rule dictates it.

### Subscriber Channel

1. Event generated by NDS.
2. Filter event using Subscriber Event Filter.
3. Apply Event Transformation Rule.
4. If event is <modify> on unassociated object, convert to <add>
5. If event is <add>
   1. Apply Matching Rule.
   2. Apply Create Rule.
   3. Apply Placement Rule.
6. Apply Command Transformation Rule.
7. Apply Schema Mapping Rule.
8. Apply Output Transformation Rule.
9. Send command(s) to driver.

### Publisher Channel

1. Event sent to DirXML by the driver.
2. Apply Input Transformation Rule.
3. Apply Schema Mapping Rule.
4. Apply Event Transformation Rule.
5. Filter event by the Publisher Event Filter.
6. If event is <modify> on unassociated object, convert to <add>
7. If event is <add>
   1. Apply Matching Rule.
   2. Apply Create Rule.
   3. Apply Placement Rule.
8. Apply Command Transformation Rule.
9. Send command(s) to NDS.

## How do the Event Filter and the rules interact with each other?

Rules and Event Filters must be explicitly constructed to complement each other. What this means really depends on the particular requirements of the installation and on the requirements of the application, but here are a few general things to keep in mind:

- If a rule operates on attribute values or uses attribute values to make a decision, those attributes need to be in the corresponding Event Filter.
- Usually a Create Rule should require all the attributes used by the Matching Rule. This forces creation of a new object to be deferred until enough is known about the object to perform a reasonable attempt at finding a matching object in the target space.

## What do I need to know to implement a rule using an XSLT stylesheet?

### Understand XSLT and the XML you will be transforming

A good working understanding of XSLT is a good place to start. Obtain the XSLT and XPath specifications. Make sure any tutorial or book reference on the subject is based on the final 16 November 1999 W3C Recommendation.

A recommended reference for XSLT programming is XSLT Programmer's Reference, by Michael Key, published by Wrox Press. ISBN 1-861003-12-9.

You also need a good working understanding of the XML specified by nds.dtd..

### Understand the goal of the rule you are implementing

Each kind of rule accomplishes specific kinds of tasks as outlined in a general fashion above. Additional things you might need to know for each rule type are:

- Input Transformation Rule
  - Performs any pre-processing of XML issued to DirXML from the driver.
  - Good place to perform data format mapping.
  - Names are in the application namespace.
  - Can change event types, generate extra events, and remove events.
- Output Transformation Rule
  - Does any post-processing of XML issued from DirXML to the driver before the XML is sent to the driver.
  - Good place to perform data format mapping.
  - Names are in the application namespace.
  - Can change event types, generate extra events, and remove events.
- Event Transformation Rule
  - Names are in the NDS namespace.
  - Can change event types, generate extra events, and remove events.
- Command Transformation Rule
  - Performs processing of XML issued from DirXML to the driver (Subscriber channel) or to eDirectory (Publisher channel) before the XML is sent to the driver or eDirectory.
  - Names are in the NDS namespace.
  - Can change command types, generate extra commands, and remove commands.
- Matching Rule
  - Only operates on <add> events
  - Names are in the NDS namespace.
  - On the Subscriber channel must add an <association> to the <add> for any matches that are found in the application.
  - On the Publisher channel must fill the dest-dn attribute of the <add> if a match is found in NDS. The special value of a single unicode character &#xFFFD; signals that multiple matches were found.
  - Cannot change event types or generate extra events.
  - Can remove events.
- Create Rule
  - Only operates on <add> events.
  - Names are in the NDS namespace.
  - Can add attributes and values to the <add> as appropriate.
  - Can remove events (this how an add is vetoed).
- Placement Rule
  - Only operates on <add> events.
  - Names are in the NDS namespace.
  - Fills in the dest-dn attribute of the <add>. For the Subscriber channel this must be in the application namespace. For the Publisher channel this must be in the NDS namespace.
  - Can remove events.

### Start out with the identity transformation

Unless you are translating to/from an XML format that is completely different from the DirXML format in the Input and Output Transformation Rules, you will want to start your stylesheet with templates that implement the identity transformation. This is so that anything in the document that you don't specifically try to intercept and change will be passed through as is.

The following two templates together implement the identity transform:

       <xsl:template match="/" >
    	  <xsl:apply-templates select="node()|@*"/>
       </xsl:template>

       <xsl:template match="node()|@*" >
    	  <xsl:copy>
    		 <xsl:apply-templates select="node()|@*"/>
    	  </xsl:copy>
       </xsl:template>

### Use the parameters that are passed into the stylesheet

Except for the Input and Output Transformation Rules, rules implemented as stylesheets are passed several parameters from DirXML that the stylesheet can use:

- fromNDS - boolean value that is true if the rule is being processed by the Subscriber channel and false if the rule is being processed by the Publisher channel.
- srcQueryProcessor - a Java object of class com.novell.nds.dirxml.driver.XdsQueryProcessor. This allows the stylesheet to query the event source for more information.
- destQueryProcessor - a Java object class com.novell.nds.dirxml.driver.XdsQueryProcessor. This allows the stylesheet to query the event target for more information.
- srcCommandProcessor - a Java object class com.novell.nds.dirxml.driver.XdsCommandProcessor. This allows the stylesheet to "write-back" a command to the event source. Not available in DirXML 1.0.
- destCommandProcessor - a Java object class com.novell.nds.dirxml.driver.XdsCommandProcessor. This allows the stylesheet to issue a command to the command destination directly, bypassing most other rules. Not available in DirXML 1.0.
- dnConverter - a Java object implementing interface com.novell.nds.dirxml.driver.DNConverter. This allows the stylesheet to convert eDirectory DNs from one DN format to another. Not available in DirXML 1.0 or DirXML 1.1.

To use these parameters include the following at the top level of your stylesheet:

       <xsl:param name="fromNDS"/>
       <xsl:param name="srcQueryProcessor"/>
       <xsl:param name="destQueryProcessor"/>
       <xsl:param name="srcCommandProcessor"/>
       <xsl:param name="destCommandProcessor"/>
       <xsl:param name="dnConverter"/>

Use of the query processors depends on the Novell XSLT implementation of extension functions. In order to make a query you need to declare a namespace for the Java interfaces used. For example, to use the XdsQueryProcessor interface add xmlns:query="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsQueryProcessor" to the <xsl:stylesheet> or <xsl:transform> element of the stylesheet.

An example of using one of the query processors:

        <!-- query object name queries NDS for the passed object-name. Ideally, this would   -->
        <!-- not depend on "CN": to do this, add another parameter that is the name of the   -->
        <!-- naming attribute.                                                               -->
        <xsl:template name="query-object-name">
           <xsl:param name="object-name"/>

           <!-- build an xds query as a result tree fragment -->
           <xsl:variable name="query">
                <!-- note: in DirXML 1.0 an <nds> and an <input> element are needed -->
               <query>
                   <search-class class-name="{ancestor-or-self::add/@class-name}"/>
                   <!-- NOTE: depends on CN being the naming attribute -->
                   <search-attr attr-name="CN">
                       <value><xsl:value-of select="$object-name"/></value>
                   </search-attr>
                   <!-- put an empty read attribute in so that we don't get the whole object back -->
                   <read-attr/>
               </query>
           </xsl:variable>

           <!-- query NDS -->
           <xsl:variable name="result" select="query:query($destQueryProcessor,$query)"/>

           <!-- return an empty or non-empty result tree fragment depending on result of query -->
           <xsl:value-of select="$result//instance"/>
        </xsl:template>

Use of the command processors depends on the Novell XSLT implementation of extension functions. In order to issue a command you need to declare a namespace for the XdsCommandProcessor interface: this is done by adding xmlns:command="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsCommandProcessor" to the <xsl:stylesheet> or <xsl:transform> element of the stylesheet.

An example of using one of the command processors:

        <!-- update full name sets the "Full Name" attribute in the event source             -->
        <!-- it expects the context node to be the <modify> element in the document          -->
        <xsl:template name="update-full-name">

           <!-- build an xds command as a result tree fragment -->
           <xsl:variable name="command">
               <modify>
                   <!-- get the association from the modify coming through -->
                   <xsl:copy-of select="association"/>
                   <!-- put in the <modify-attr> for the Full Name attribute -->
                   <modify-attr attr-name="Full Name">
                       <remove-all-values/>
                       <add-value>
                           <value>
                               <xsl:value-of select="modify-attr[@attr-name='Given Name']/add-value/value"/>
                               <xsl:text> </xsl:text>
                               <xsl:value-of select="modify-attr[@attr-name='Surname']/add-value/value"/>
                           </value>
                       </add-value>
                   </modify-attr>
               </modify>
           </xsl:variable>

           <!-- send command to source -->
           <xsl:variable name="result" select="command:execute($srcCommandProcessor,$command)"/>
        </xsl:template>

### Use extension functions as needed

XSLT is an excellent tool for performing some kinds of transformations and a rather poor tool for other types of transformations (non-trivial string manipulation, iterative processes, etc.). Fortunately the Novell XSLT processor implements extension functions which allow the stylesheet to call a function implemented in Java (and by extension any other language that can be accessed through JNI).

Additional documentation on using extension functions with Novell's XSLT implementation can be found elsewhere. For specific examples see the above example using the query processor, and the following example that illustrates using Java for string manipulation:

        <!-- get-dn-prefix places the part of the passed dn that precedes the   -->
        <!-- last occurrence of '\' in the passed dn in a result tree fragment  -->
        <!-- meaning that it can be used to assign a variable value             -->
        <xsl:template name="get-dn-prefix" xmlns:jstring="http://www.novell.com/nxsl/java/java.lang.String">
           <xsl:param name="src-dn"/>

           <!-- use java string stuff to make this much easier -->
           <xsl:variable name="dn" select="jstring:new($src-dn)"/>
           <xsl:variable name="index" select="jstring:lastIndexOf($dn,'\')"/>
           <xsl:if test="$index != -1">
              <xsl:value-of select="jstring:substring($dn,0,$index)"/>
           </xsl:if>
        </xsl:template>

## How do I invoke the Novell XSLT processor directly?

Drivers can invoke the Novell XSLT processor directly by using the com.novell.xsl.StyleSheet class. There are various ways in which this can be set up and invoked so it pays to read the documentation, but a typical invocation is illustrated by the following code fragment.

    import com.novell.nds.dirxml.driver.*;
    import com.novell.xsl.*;
    import com.novell.xsl.result.*;
    import org.w3c.dom.*;
    .
    .
    .
       try
       {
          XmlDocument inputDoc = new XmlDocument();
          XmlDocument stylesheetDoc = new XmlDocument();

          // load the input and stylesheet documents from a file
          inputDoc.readDocument(new FileInputStream("input.xml"));
          stylesheetDoc.readDocument(new FileInputStream("stylesheet.xsl"));

          // create the stylesheet processor and give it the stylesheet
          Stylesheet  styleSheet = new Stylesheet();
          styleSheet.load(stylesheetDoc.getDocument());

          // pass in any stylesheet parameters that the stylesheet might need
          styleSheet.setParameter("fromNds", new Boolean(fromNDS));

          // setup a result handler to get a DOM tree
          Document resultDoc = com.novell.xml.dom.DocumentFactory.newDocument();
          DOMResultHandler resultHandler = new DOMResultHandler(resultDoc);
          styleSheet.setResultHandler(resultHandler);

          // apply the stylesheet
          styleSheet.process(doc, null);

          // result will be in resultDoc

       }
       catch( XSLException xsle )
       {
          // handle any exception thrown
       }

## Are there any other utility classes available to make my job easier?

There are a number of utility classes provided by DirXML or nxsl.jar that are useful to driver writers. Among the most useful are:

- com.novell.xml.dom.DOMQuery - A class that uses XPath expressions to find nodes in a DOM tree.
- com.novell.xml.dom.DOMUtil - Utility class implementing, among others, things that XSLT and DirXML need for DOM that aren't defined by the 1.0 DOM spec (namespaces, serialization, whitespace stripping, id resolution, etc.).
- com.novell.xml.dom.DOMWriter - A class for serializing DOM trees, used by XmlDocument and DOMUtil. Using this class directly allows for finer control of the serialization process.
- com.novell.xsl.util.Util - Has a method called getXSLStringValue() which evaluates the string value of a Node according to the XPath definition. Useful for the text content of an Element.
- com.novell.nds.dirxml.driver.DriverFilter and com.novell.nds.dirxml.driver.ClassFilter - Allows easy use of the Publisher Event Filter or the Subscriber Event Filter passed to the shim init() method.
- com.novell.nds.dirxml.driver.Trace - Facility for drivers to use to output debugging trace messages to the DSTRACE console and to the DirXML log file.
- com.novell.nds.dirxml.driver.DelimitedText - class for representing a delimited text file as XML.
- com.novell.nds.dirxml.driver.ThreadBridge - implements a method of calling methods on a different thread.
- com.novell.xml.util.Base64Codec - implements encoding and decoding of binary data using Base64 encoding. Base64 encoding is used by DirXML to encode binary data in command and event notification documents.
- com.novell.nds.dirxml.driver.ThreadGroupLocal - implements a storage of variables local to the threads used for a driver (subscriber and publisher threads).
- com.novell.nds.dirxml.driver.DNConverter - interface usable from stylesheet rules for converting eDirectory DNs from one DN format to another.

## Does my driver have to do anything special to work with the DirXML Remote Loader?

The short answer is: no.

The long answer is: If your driver makes assumptions about where it is running it may need to be modified. If, for example, your driver uses a "side-band" connection to eDirectory via LDAP and assumes it can do so on "localhost" then your driver won't work correctly with the Remote Loader. In general, if your driver strictly adheres to the DirXML interfaces and doesn't assume that it is running on the same machine as eDirectory then your driver will function properly with the DirXML Remote Loader.

## How can I debug my driver or rules?

### Use DSTRACE.

Messages originating from DirXML show up in DSTRACE if you enable the DirXML Drivers events (DVRS on NetWARE). By default very little information is given, mostly just the status of events. To enable more verbose output, add the DirXML-DriverTraceLevel attribute to the DirXML-DriverSet object using Other tab on the ConsoleOne Properties dialog. Useful values for this attribute are:

- 1 - Informational messages about what DirXML is doing;
- 2 - adds dumps of the XML passed to/from the driver;
- 3 - adds XML dumps after a stylesheet is applied and more verbose output during rule evaluation.

Drivers may also send messages to DSTRACE by creating and using an instance of com.novell.nds.dirxml.driver.Trace. It is recommended that drivers not write directly to System.out or System.err (even though this will currently send the output to DSTRACE) because this may not be supported in future releases.

Trace messages may also be directed to a file (in addition to DSTRACE) by setting the value of the DirXML-JavaTraceFile attribute on the DirXML-DriverSet object to a valid filename. Use the Other tab on the ConsoleOne Properties dialog for the DirXML-DriverSet object.

### Attach a Java debugger (This is currently only supported on Win32).

There are a number of Java debuggers available and two common debugger APIs on the Java platform.

#### Agent Debugger

1. Obtain a copy of JDK 1.3.0.
2. Make a backup copy of the DirXML jre directory (typically C:\Novell\Nds\jre).
3. Delete the DirXML jre directory.
4. Copy the jre directory from the JDK into the DirXML jre directory.
5. Copy the contents of the jdk lib directory (jdk/lib) into the DirXML jre/lib directory (tools.jar, etc.).
6. Add the DirXML-JavaDebugPort attribute to the DirXML-DriverSet object (use the Other tab in the ConsoleOne Properties dialog for the DirXML-DriverSet object).
7. Set the DirXML-JavaDebugPort value to a TCP port value not in use on your machine (8080 usually works).
8. Restart NDS.
9. Before the first driver in the driver set starts a dialog box will pop up informing you of the debugger password. At this point you can attach a debugger to the JVM and press OK. You can also press OK without attaching a debugger.

#### JavaTM Platform Debugger Architecture (JPDA)

1. Obtain a copy of JDK 1.3.0.
2. Copy the jdwp.dll, dt_shmem.dll, and dt_socket.dll from the bin directory in the JDK into the NDS directory.
3. Set the appropriate debug options in the DHOST_JVM_OPTIONS environment variable (See http://java.sun.com/products/jpda for details).
   Sample: set DHOST_JVM_OPTIONS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=8080,suspend=n
   Note that if running as a server, you must set this in the System control panel under System variables.
4. Restart NDS.
5. Before the first driver in the driver set starts a dialog box will pop up informing you that you that Java 2 debugging is enabled . At this point you can attach a debugger to the JVM and press OK. You can also press OK without attaching a debugger.

#### Using the Visual Cafe 3.0 Debugger

The Visual Cafe debugger is an agent-type debugger. To setup a debugging session:

1. Create a project to use for debugging.
2. Set the main class to sun.tools.agent.EmptyApp.
3. Set the source directories and input class files directories appropriately for your environment.
4. Attach the debugger to the DirXML JVM using Projects | Debug in Waiting VM. Use localhost as the host name and the password supplied by the dialog box mentioned above.

#### Using jdb

The jdb is an agent-type debugger. To setup a debugging session:

1. Enter the following command on the command line
   jdb -host localhost -password <password>
2. Set the path to your source directories using the "use" command"
3. You can create a file named "startup.jdb" in the working directory that can contain commands that will be executed when jdb starts. This is a good place to put the "use" command.

#### Using CodeWarrior 5 debugger

CodeWarrior supports both agent and JPDA debugging API's. To setup a debugging session:

1. Add the registry key "HKEY_LOCAL_MACHINE\SOFTWARE\Metrowerks\CodeWarrior\4.0\Java VMs" if it doesn't already exist.
2. Add to that key the String value "JDWP debug ports" for JPDA debugging or "11XWP debug ports" for Agent debugging.
3. Set the value to be the port number that DirXML was set up to use. Note that contrary to the documentation, apparently CodeWarrior does not seem to recognize ports greater than 9999 or more than 1 port for each value.
4. Start CodeWarrior.
5. Open the class or jar file that you wish to debug.
6. Choose SunJavaPlugin.dll when asked to choose the debugger.
7. Select Window | Process Window to open the Processes window.
8. Select the entry "JDWP debug port XXXX (inactive)" or "11XWP debug port XXXX (inactive)" (where XXXX is the port number you are using).
9. Press the attach to process button.
10. For more information see the CodeWarrior help topic: Help | Other... | Targeting Java VM | Debugging Java Projects | Debugging External Java Sessions (Windows Only).

#### Notes

- Usually you can attach a debugger after you have dismissed the DirXML dialog that pauses, waiting for you to attach to the JVM.
- If you stop the debugging session in VisualCafe or jdb it shuts down the DirXML JVM running in the NDS process and you will have to restart NDS to get it back up again.
- The VisualCafe 3.0 debugger has a lot of quirks:
  - Occasionally it has trouble attaching to the JVM.
  - Sometimes it gets internal java exceptions, after which no data will display until you shutdown VisualCafe and restart it.
  - Often it will still stop at breakpoints that have been removed or disabled.
- The password is really just an obfuscated version of the port number. Since you are picking a static port number you can reuse any of the passwords that are generated. If you see one that is easy to memorize, remember and use it instead of using a new password everytime.

### Environment Variables

#### The following environment variables can be used on Win32:

DHOST_JVM_USE_VFPRINTF | If set to a value other than "0"; will cause installation of a vfprintf hook function that will write to a log file named "jvm_vfprintf.log"; in the temp directory. This will also enable verbose class and JNI messages.
DHOST_JVM_VERBOSE_GC | If set to a value other than "0"; will enable verbose garbage collector messages. This is only useful in conjunction with JVM_USE_VFPRINTF.
DHOST_JVM_INITIAL_HEAP | Set to value in decimal number of bytes of initial JVM heap size.
DHOST_JVM_MAX_HEAP | Set to value in decimal number of bytes of maximum JVM heap size.
DHOST_JVM_OPTIONS | Set to arguments for the 1.2 JVM. Example: `-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=8080,suspend=n` Each option string is separated by whitespace. If an option string contains whitespace, it must be enclosed in double quotes.
DHOST_JVM_DESTROY | If set to a value other than "0"; will cause the JVM loader thread to call DestroyJavaVM() when DirXML is unloaded. This is useful to cause the Java 2 hprof profiler to dump its data to a file. Note that the JVM is unusable after this call and CANNOT be reloaded (thank Sun for that). DHOST must be shutdown and restarted to use the JVM again (this means DirXML cannot be restarted until DHOST has restarted).

#### The following options can be used on NetWare:

DIRXML_JVM_INITIAL_HEAP | set to value in bytes of initial java heap size. Works with 1.1.x and 1.2.x. Example: `DIRXML_JVM_INITIAL_HEAP=4M` Example: `DIRXML_JVM_INITIAL_HEAP=4096K`
DIRXML_JVM_MAX_HEAP | set to value in decimal bytes of maximum java heap size. Works with 1.1.x and 1.2.x. Example: `DIRXML_JVM_MAX_HEAP=36M` Example: `DIRXML_JVM_MAX_HEAP=36864K`
DIRXML_JVM_VIRTUAL_HEAP | set to value in decimal bytes of virtual java heap size. Works with 1.1.x and 1.2.x. Example: `DIRXML_JVM_VIRTUAL_HEAP=36M` Example: `DIRXML_JVM_VIRTUAL_HEAP=36864K`
DIRXML_JVM_OPTIONS | set to arguments for the 1.2 JVM. Example: `-Xnoagent -Xdebug -Xdebugport8080 -Xmx36M` Each option string is separated by whitespace. If an option string contains whitespace, it must be enclosed in double quotes. DHOST_JVM_OPTIONS only works with 1.2.x.
DIRXML_JVM_C_STACK_SIZE | set to value in decimal bytes of the java C process stack size. Example: `DIRXML_JVM_C_STACK_SIZE=128K (default)` Example: `DIRXML_JVM_C_STACK_SIZE=256K`