Novell Home

Reporting on eDirectory Objects with XSLT

Novell Cool Solutions: Feature
By Michel Bluteau

Digg This - Slashdot This

Posted: 21 Oct 2005
 

I have been exploring over the years several ways of generating reports on eDirectory objects, mainly users and groups. This article describes one way of generating a simple reports on user objects. It also shows how to send the report by e-mail as an attachment to the admin, as well as providing a URL for accessing the report from a web server.

This approach should be considered as an example only, and more customization would be expected to meet your specific needs.

I decided to leverage XSLT instead of Policy Builder, because it allows for queries against eDirectory to be more flexible.

The solution includes one stylesheet that can be added to an existing driver, or a loopback driver. Actions that trigger the creation of a report could range from a specific event (an attribute is modified for a given object) to a change of date (daily report). For daily reports, you can read my article on time- triggered events:

http://www.novell.com/coolsolutions/tip/8619.html

Before you begin, be sure to copy DirXMLSmallUtils.jar to your /lib directory for eDirectory. This .jar file has been included with other articles from CoolSolutions, and its classes are used by the XSLT. Then restart eDirectory.

XSLT Stylesheet

The following is the entire stylesheet:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:ncs="http://www.novell.com/nxsl/java/com.novell.ncs.dirxml.utilities.Utils" xmlns:query="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsQueryProcessor" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <!--    _________________       Report User objects under qc/ca/mrq/identite _______________________________________ -->
        <!--    _________________       Created by Michel Bluteau mbluteau@novell.com  __________________ -->
        <xsl:param name="srcQueryProcessor"/>
        <xsl:template match="node()|@*">
                <xsl:copy>
                        <xsl:apply-templates select="node()|@*"/>
                </xsl:copy>
        </xsl:template>
        <!--    _________________       Catch modify on User class __________________ -->
        <xsl:template match="modify-attr[@attr-name='Title']">
                <!--    _________________       Copy attributes we don't want to mess with __________________ -->
                <xsl:variable name="report" select="add-value/value"/>
                <xsl:message>We are in XSLT Reports-Users, report = <xsl:value-of select="$report"/>
                </xsl:message>
                <xsl:if test="$report='Report-Users'">
                        <xsl:variable name="filename" select="concat(ncs:getTimeString(),'.htm')"/>
                        <xsl:variable name="file" select="concat('/var/opt/novell/tomcat4/webapps/nps/reports/',$filename)"/>
                        <xsl:variable name="fileurl" select="concat('http://192.168.1.19/nps/reports/',$filename)"/>
                        <xsl:copy>
                                <xsl:apply-templates select="node()|@*"/>
                        </xsl:copy>
                        <!--    _________________       Query eDirectory for existing attributes __________________ -->
                        <xsl:variable name="src-query">
                                <query dest-dn="tree\org\identity" scope="subtree">
                                        <read-attr attr-name="CN"/>
                                </query>
                        </xsl:variable>
                        <!--    _________________       Paste exiting attributes into variables __________________ -->
                        <xsl:variable name="result" select="query:query($srcQueryProcessor, $src-query)"/>
                        <xsl:variable name="cn" select="$result//value"/>
                        <!--    _________________       Create the Report file __________________ -->
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<HTML>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<HEAD>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<TITLE>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'Report on Users')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</TITLE>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</HEAD>')"/>
                        </xsl:message>
                        <xsl:message>CR:<xsl:value-of select="ncs:writeLog($file,' ')"/>
                        </xsl:message>
                        <xsl:for-each select="$cn">
                                <xsl:variable name="DN" select="concat('tree\org\identity\',.)"/>
                                <!--    _________________       Query eDirectory for existing attributes __________________ -->
                                <xsl:variable name="src-query2">
                                        <query class-name="User" dest-dn="{$DN}" scope="entry">
                                                <read-attr attr-name="Surname"/>
                                                <read-attr attr-name="Given Name"/>
                                        </query>
                                </xsl:variable>
                                <!--    _________________       Paste exiting attributes into variables __________________ -->
                                <xsl:variable name="result2" select="query:query($srcQueryProcessor, $src-query2)"/>
                                <xsl:variable name="surname" select="concat('Surname = ',$result2/nds/output/instance[1]/attr[@attr-name='Surname']/value[1])"/>
                                <xsl:variable name="givenname" select="concat('Given Name = ',$result2/nds/output/instance[1]/attr[@attr-name='Given Name']/value[1])"/>
                                <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<P>')"/>
                                </xsl:message>
                                <xsl:message>DN:<xsl:value-of select="ncs:writeLog($file,$DN)"/>
                                </xsl:message>
                                <xsl:message>Surname:<xsl:value-of select="ncs:writeLog($file,$surname)"/>
                                </xsl:message>
                                <xsl:message>Given Name:<xsl:value-of select="ncs:writeLog($file,$givenname)"/>
                                </xsl:message>
                                <xsl:message>CR:<xsl:value-of select="ncs:writeLog($file,' ')"/>
                                </xsl:message>
                        </xsl:for-each>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</HTML>')"/>
                        </xsl:message>
                        <!--    _________________       End of create Report file __________________ -->
                        <!-- public static boolean sendMail(java.lang.String from,
                                                            java.lang.String to,
                                                            java.lang.String subj,
                                                            java.lang.String msgText,
                                                            java.lang.String file,
                                                            java.lang.String host,
                                                            java.lang.String debugging)
                        -->
                        <xsl:message>Sending eMail:<xsl:value-of select="ncs:sendMail('meta@novl.ca','mbluteau@novell.com','Report on Users',$fileurl,$file,'24.201.245.36','true')"/>
                        </xsl:message>
                </xsl:if>
        </xsl:template>
</xsl:stylesheet>

Notes on the Example

Below are some explanations of how the example works. I decided to use the Title attribute for triggering my report:

<xsl:template match="modify-attr[@attr-name='Title']">

Then I created a few variables for the name of a file to be posted on my web server, and also for its URL. I used my Tomcat installation for iManager 2.5 as my web server:

                        <xsl:variable name="filename" select="concat(ncs:getTimeString(),'.htm')"/>
                        <xsl:variable name="file" select="concat('/var/opt/novell/tomcat4/webapps/nps/reports/',$filename)"/>
                        <xsl:variable name="fileurl" select="concat('http://192.168.1.19/nps/reports/',$filename)"/>

Then I queried eDirectory under a OU in order to get a list of users(CN):

<!--    _________________       Query eDirectory for existing attributes __________________ -->
                        <xsl:variable name="src-query">
                                <query dest-dn="tree\org\identity" scope="subtree">
                                        <read-attr attr-name="CN"/>
                                </query>
                        </xsl:variable>
                        <!--    _________________       Paste exiting attributes into variables __________________ -->
                        <xsl:variable name="result" select="query:query($srcQueryProcessor, $src-query)"/>
                        <xsl:variable name="cn" select="$result//value"/>
 Then I start creating the report in HTML format using the writeLog class:

                        <!--    _________________       Create the Report file __________________ -->
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<HTML>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<HEAD>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<TITLE>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'Report on Users')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</TITLE>')"/>
                        </xsl:message>
                        <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</HEAD>')"/>
                        </xsl:message>
                        <xsl:message>CR:<xsl:value-of select="ncs:writeLog($file,' ')"/>
                        </xsl:message>

Note the use of escape characters such as "<". In XML, those characters have special meaning, so they must be substituted with corresponding escape characters.

Then I used a for-each block to process each and every user object, and added a line to the report:

<xsl:for-each select="$cn">
                                <xsl:variable name="DN" select="concat('tree\org\identity\',.)"/>
                                <!--    _________________       Query eDirectory for existing attributes __________________ -->
                                <xsl:variable name="src-query2">
                                        <query class-name="User" dest-dn="{$DN}" scope="entry">
                                                <read-attr attr-name="Surname"/>
                                                <read-attr attr-name="Given Name"/>
                                        </query>
                                </xsl:variable>
                                <!--    _________________       Paste exiting attributes into variables __________________ -->
                                <xsl:variable name="result2" select="query:query($srcQueryProcessor, $src-query2)"/>
                                <xsl:variable name="surname" select="concat('Surname = ',$result2/nds/output/instance[1]/attr[@attr-name='Surname']/value[1])"/>
                                <xsl:variable name="givenname" select="concat('Given Name = ',$result2/nds/output/instance[1]/attr[@attr-name='Given Name']/value[1])"/>
                                <xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'<P>')"/>
                                </xsl:message>
                                <xsl:message>DN:<xsl:value-of select="ncs:writeLog($file,$DN)"/>
                                </xsl:message>
                                <xsl:message>Surname:<xsl:value-of select="ncs:writeLog($file,$surname)"/>
                                </xsl:message>
                                <xsl:message>Given Name:<xsl:value-of select="ncs:writeLog($file,$givenname)"/>
                                </xsl:message>
                                <xsl:message>CR:<xsl:value-of select="ncs:writeLog($file,' ')"/>
                                </xsl:message>
                        </xsl:for-each>

Then I closed the report file:

<xsl:message>Report:<xsl:value-of select="ncs:writeLog($file,'</HTML>')"/>
                        </xsl:message>

The last step is to send the e-mail using the sendMail class. A SMTP relay host is required at this point. I used the one from my ISP, but in real life a more secure host is preferred:

<!-- public static boolean sendMail(java.lang.String from,
                                                            java.lang.String to,
                                                            java.lang.String subj,
                                                            java.lang.String msgText,
                                                            java.lang.String file,
                                                            java.lang.String host,
                                                            java.lang.String debugging)
                        -->
                        <xsl:message>Sending eMail:<xsl:value-of select="ncs:sendMail('meta@novl.ca','mbluteau@novell.com','Report on Users',$fileurl,$file,'24.201.245.36','true')"/>
                        </xsl:message>

Customizations

Of course, the above example is a very generic one, but the key ideas are there. For example, you could create one XSLT for each type of report (on users, on groups, etc.) and allow admins to request reports through iManager using a form created with Plug-in Studio, etc.

The source for such a report would look like this:

<HTML>
<HEAD>
<TITLE>
Report on Users
</TITLE>
</HEAD>
 
<P>
tree\org\identity\user601
Surname = 601
Given Name = user
 
<P>
tree\org\identity\user602
Surname = 602
Given Name = user
 
</HTML>

I hope this example proves useful to you. I welcome any feedback, suggestions or questions.


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell