Monday, October 20, 2008

Using LDAP (or javaLDAP) in ColdFusion

We are using URLAuth within IIS to provide Authorization to our website.  This process uses a VBScript to run some code and return success or failure.  Right now, we implemented a database with a stored procedure to hit some complicated structure of tables to provide Directory/Role/Group/User association.  

PSU now provides a great resource with there main LDAP directory, where Offices/Users can create and manage their own Groups.  Therefore, the Admissions office, can have access to the Registrar's groups. 

But to make the transition easy, I wrote a page within Coldfusion to grab all the "groups" in our database and go attack the LDAP server.  This provided many LDAP calls within the same page.  The LDAP server had no issue with us hitting it many times within a short period, but Coldfusion started barfing all over the place!!

The error we were receiving was unable to create new native thread null.  After a while, I found this blog, about a similar issue.  His solution was to use javaLDAP, which the java code is provided by Novell, and there is a corresponding javaLDAP.cfc.


Friday, October 17, 2008

ColdFusion - ValidationExceptions

I've been in java training for a while now, and within java the best practice is to throw an Exception anytime you want to return a message from one method to the calling method. So for example, a method doValidate would return true/false, but we would actually want the messages of what failed validation if it returned false. Well instead of returning false we would throw an exception.

Well in base coldfusion, the only thing we can do is throw one message at a time, so it doesn't make sense to code it that way. Well if you are like me, I really like the throw concept, an it doesn't make sense to add a bunch of code just to return false w/ a structure of the messages!!!

<cfthrow errorcode="" message="" detail="" extendedInfo="">


That being said, and since Coldfusion is built on top of java, all you need to do is write a java program that extends RunTimeException. I have done just that were the Java Class has the capability of storing multiple messages. And then you can throw that object as the error.

<cfthrow obj="">


Here is my Java Code
import java.util.ArrayList;

public class ValidationException extends RuntimeException {
     private ArrayList validationError = new ArrayList(); // [ExceptionNumber][errorCode | message | detail | extendedInfo]

    public ValidationException() { super(); }

    public ValidationException(String message) { super(message); }

    public boolean hasValidationError() {
        if (validationError.size() == 0) {
            return false;
        } else {
            return true;
        }
    }

    public void addValidationError(String errorCode, String message, String detail, String extendedInfo) {
        ValidationError curError = new ValidationError(errorCode, message, detail, extendedInfo);        
        validationError.add(curError);
    }
    
    public void addValidationError(String message) {
        addValidationError("", message, "", "");
    }
    
    public ValidationError getValidationError(int x) {
        return (ValidationError)validationError.get(x);
    }
    
    public int length() {
        return validationError.size();
    }
}


Here is my Example Coldfusion Code

METHOD WITHIN CFC

<cffunction name="doValidate" output="true" access="public" hint="validation of campaign Setup">
        <cfset var eValidate = "">
        <cfset eValidate = CreateObject("java", "edu.psu.uao.exceptions.ValidationException").init("Validation Error")>
        
        <cfif trim(variables.instance.CampaignName) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.1","Campaign Name is Required","","")>
        </cfif>        
        <cfif trim(variables.instance.CampaignActive) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.2","Campaign Active is Required","","")>
        </cfif>
        <cfif trim(variables.instance.campaignTypeID) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.3","Campaign Type is Required","","")>            
        </cfif>
        <cfif trim(variables.instance.campaignPopulationDelay) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.4","Campaign Population Delay is Required","","")>
        </cfif>
        <cfif trim(variables.instance.campaignPopulationRefresh) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.5","Campaign Population Refresh is Required","","")>
        </cfif>
        <cfif trim(variables.instance.CampaignPoolID) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.6","Campaign Pool is Required","","")>
        </cfif>
        <cfif trim(variables.instance.CreatedBy) EQ "">
            <cfset eValidate.addValidationError("cfc.service.crm.campaign.doValidate.7","Campaign Created By is Required","","")>
        </cfif>
        
        <cfif eValidate.hasValidationError()>
            <cfthrow object="#eValidate#">
        </cfif>

    </cffunction>



CALLING CFM PAGE



<cftry>

    <cfset oCamp.doValidate()>
    

    <cfcatch type="edu.psu.uao.exceptions.ValidationException">        
        <cfset ve = cfcatch>
        <cfoutput>
        <cfloop index="x" from="0" to="#Val(ve.length()-1)#">
            <cfset cve = ve.getValidationError(javaCast('int',x))>
            errorCode: #cve.getErrorCode()#
            message: #cve.getMessage()#
            details: #cve.getDetail()#
            extendedInfo: #cve.getExtendedInfo()#
        </cfloop>
        </cfoutput>
    </cfcatch>
    <cfcatch type="Any">
        all done
<cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

Make ColdFusion Sleep

I've been in java training now for 6 weeks, and I have been adding "java" code to Coldfusion.  For example, I added a new "Exception" to coldfusion to allow my code to throw an error that has multiple message in that error.  This is great for server side Validation !!!  Where my code checks all the validation rules and adds the errors to the Exception code, and at the end of the method if there is one error, it does a cfthrow with that java Exception object.  More details on java ValidationException here...

But I wanted to test the "thread" safe of this java code within coldFusion, since I am not sure how CF has there Code written.  So to do this, i had a page store the Exception in memory and use it from two pages.  But I wanted the 1st page to start first and end last, and the 2nd page to start last and end first.   HMMM how can i do that.  Well, I added a SLEEP routine to the pages.  Of course, I didn't know how to do this, so I found this bit of code from Duncan Loxton's Blog.

<cfset thread = CreateObject("java", "java.lang.Thread")>

<cfset thread.sleep(5000)>