Behold, Axe Cop, the most awesome comic ever!

Axe Cop

Axe Cop

Ethan Nicolle is a 29 year old comic artist/author.  Malachai Nicolle is his 5 year old brother.  Together, they produce Axe Cop.  Malachai writes the stories, and Ethan illustrates them.  If you’ve ever spent much time with or as a 5 year old boy, you already know where this will lead.  If not, I will tell you, it leads to the most awesome comic book ever written.

Invoking a Task via XPRESS in Sun’s Identity Manager 7.1

Occasionally, I’ve wanted to invoke an Identity Manager Task from within a rule in XPRESS. Here is a rule that will do that:

<Rule name="runTask">
    <RuleArgument name='taskName'/>
    <RuleArgument name='taskVariables'/>
    <RuleArgument name='execMode'/>
    
    <block>
        <defvar name='processView'>
            <new class='com.waveset.object.GenericObject'>
                <ref>taskVariables</ref>
            </new>
        </defvar>
        
        <invoke name='setId'>
            <ref>processView</ref>
            <s>Process</s>
        </invoke>
        
        <invoke name='put'>
            <ref>processView</ref>
            <s>task.process</s>
            <ref>taskName</ref>
        </invoke>
        
        <invoke name='put'>
            <ref>processView</ref>
            <s>task.taskName</s>
            <ref>taskName</ref>
        </invoke>
        
        <cond>
            <ref>execMode</ref>
            <invoke name='put'>
                <ref>processView</ref>
                <s>task.execMode</s>
                <ref>execMode</ref>
            </invoke>
        </cond>
        
        <invoke name='checkinView'>
            <rule name='getCallerSession'/>
            <ref>processView</ref>
            <null/>
        </invoke>
    </block>
</Rule>

And here is a sample invocation:

<rule name='runTask'>
    <argument name='taskName' value='myTask'/>
    <argument name='taskVariables'>
        <map>
            <s>taskArgument1</s>
            <ref>myVariable</ref>
            <s>taskArgument2</s>
            <s>String Data</s>
        </map>
    </argument>
    <argument name='execMode' value='async'/>
</rule>

The value of execMode should be one of the following:

sync
Specifies synchronous or foreground execution
async
Specifies asynchronous or background execution
asyncImmediate
Specifies asynchronous with immediate thread launch

HTTP File Uploads with Sun’s Identity Manager 7.1

Identity Manager has a display class called FileUpload which you can use to do HTTP File Uploads. In a form, it would look something like this:

<Field name='fileUpload'>
    <Display class='FileUpload'>
        <Property name='Title' value='File to upload'/>
    </Display>
</Field>

In the above example, the field fileUpload would be set to an object of type DataSource. I want to use the contents of the file as a string in my XPRESS rules, but how do I do that?

The most obvious thing to try would be to invoke the appropriate java directly from XPRESS. Here is a rule that does that:

<Rule name="getStringFromFileUpload">
    <RuleArgument name='fileUpload'/>
 
    <block>
        <defvar name='bufferedReader'>
            <new class='java.io.BufferedReader'>
                <new class="java.io.InputStreamReader">
                    <invoke name='getInputStream'>
                        <ref>fileUpload</ref>
                    </invoke>
                </new>
            </new>
        </defvar>
         
        <defvar name='fileContentAsString'/>
         
        <defvar name='nextLine'>
            <invoke name='readLine'>
                <ref>bufferedReader</ref>
            </invoke>
        </defvar>
         
        <while>
            <notnull>
                <ref>nextLine</ref>
            </notnull>
            <block>
                <setvar name='fileContentAsString'>
                    <concat>
                        <ref>fileContentAsString</ref>
                        <ref>nextLine</ref>
                    </concat>
                </setvar>
                <setvar name='nextLine'>
                    <invoke name='readLine'>
                        <ref>bufferedReader</ref>
                    </invoke>
                </setvar>
            </block>
        </while>
        <ref>fileContentAsString</ref>
    </block>
</Rule>

Unfortunately, when I attempt that, I get this:

XPRESS exception ==> com.waveset.util.WavesetException: XPRESS exception ==> com.waveset.util.WavesetException: XPRESS exception ==> com.waveset.util.WavesetException: Couldn’t find method getInputStream() in class com.waveset.ui.util.BufferedRequest$AttachmentDataSource

That’s odd, because there really is a method called getInputStream on AttachmentDataSource. Ah well, so I seem to have hit a bug in XPRESS. No bother, I’ll just try invoking the appropriate Java in Javascript. Here is a rule that does that:

<Rule name="getStringFromFileUpload">
    <RuleArgument name='fileUpload'/>
 
    <script>
        importPackage(Packages.javax.activation);
        importPackage(Packages.com.waveset.ui.util);
        importPackage(Packages.java.io);
        importPackage(Packages.java.lang);
       
        var attachment = env.get('fileUpload');
       
        var fileContentsAsString = '';
       
        try {
       
            var bufferedReader = new BufferedReader(new InputStreamReader(attachment.getInputStream()));
       
            var line = '';
       
            while ((line = bufferedReader.readLine()) != null) {
                fileContentsAsString += line + "\n";
            }
        }
            catch(err) {
            result = err.getMessage();
        }
         
        fileContentsAsString;
    </script>
</Rule>

Hmm, no dice that way, either:

org.mozilla.javascript.EvaluatorException: Class org.mozilla.javascript.NativeJavaMethod can not access a member of class com.waveset.ui.util.BufferedRequest$AttachmentDataSource with modifiers “public”

OK, so it seems that it’s not just XPRESS, but Javascript also has a problem invoking the method. The only solution I could find is to write a custom bit of Java to do the actual work like this:

package net.woogie.idm.util;
 
import java.io.*;
import javax.activation.*;
import com.waveset.ui.util.*;
 
public class Attachment {
 
    public Attachment() {
    }
 
    public String toString(DataSource attachment) throws IOException {
 
        String fileContentsAsString = "";
 
        try {
            InputStream inputStream = attachment.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
 
            String line;
 
            while ((line = bufferedReader.readLine()) != null) {
                fileContentsAsString += line + "\n";
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
 
        return fileContentsAsString;
    }
}

And to invoke it via XPRESS like this:

<Rule name="getStringFromFileUpload">
    <RuleArgument name='fileUpload'/>
 
    <invoke name='toString'>
        <new class='net.woogie.idm.util.Attachment'/>
        <ref>fileUpload</ref>
    </invoke>
</Rule>

This works, but it sort of bums me out because it would be nice to have an XML only solution to this.