I have been building a list of CFC best practices to share.
There are a numerous of articles out there but I thought it might be neat to get any tricks and tips together here in one place that have been learnt through experience.
I'll add a few links here to get it going but I think the best thing would be not long articles that can be googled.
CFC Best Practices
Macromedia CFC Best Practices
Update: This has been made into a community wiki
O'Reilly's Top Ten Tips for Developing ColdFusion Components
Four quick things:
Get on the CFCDev mailing list (or google groups as it is now).
PDF of a Design Patterns in CFML presentation by Sean Corfield is a good quick read.
http://www.cfdesignpatterns.com has some good stuff with links to quality CFC design articles.
Article on the design patterns in CFML on Rob Brooks-Bilson's Blog .
Prior to using the ColdBox Framework I did not see any posts about using Momentos to capture the properties at that moment; however, now all my beans have a getMomento() and setMomento() method. I would encourage this as a best practice for anyone who needs to pass information from a bean into a DAO other object.
In my tests, getting a momento is much faster than passing the bean and getting the properties. Here is an example:
<cfcomponent name="userBean" output="true" hint="The account bean holds getter/setter information for a user's account.">
<cfproperty name="idUser" required="true" type="string" rules="noZeroLengthString,validEmail" invalidMessage="failed_data_validation_email" hint="Key matching the 'accounts' table.">
<cfproperty name="loginEmail" required="true" type="string" rules="noZeroLengthString,validEmail" invalidMessage="failed_data_validation_email" hint="E-mail address.">
<cfproperty name="password" required="true" type="string" rules="noZeroLengthString,validPassword" invalidMessage="failed_data_validation_password" hint="Password stored in a SHA-512 hash.">
<cffunction name="init" output="false" returntype="userBean" hint="Initalizes the userBean with default values.">
<cfset variables.instance = structNew()>
<cfset variables.instance.IDUser = 0>
<cfset variables.instance.loginEmail = "">
<cfset variables.instance.password = "">
<cfreturn this>
</cffunction>
<!--- SET LOGIN --->
<cffunction name="setLoginEmail" access="public" returntype="void" output="false">
<cfargument name="email" type="string" required="true" />
<cfset variables.instance.loginEmail = trim(arguments.email) />
</cffunction>
<cffunction name="getLoginEmail" access="public" returntype="string" output="false">
<cfreturn variables.instance.loginEmail />
</cffunction>
<!--- ID --->
<cffunction name="setIDUser" access="public" returntype="void" output="false">
<cfargument name="id" type="numeric" required="true" />
<cfset variables.instance.IDUser = arguments.id />
</cffunction>
<cffunction name="getIDUser" access="public" returntype="numeric" output="false">
<cfreturn variables.instance.IDUser />
</cffunction>
<!--- PASSWORD --->
<cffunction name="setPassword" access="public" returntype="void" output="false">
<cfargument name="password" type="string" required="true" />
<cfset var pw = arguments.password>
<cfif len(pw) EQ 0>
<cfset variables.instance.password = "">
<cfelse>
<!---><cfset variables.instance.password = hash(arguments.password, "SHA-512") />--->
<cfset variables.instance.password = arguments.password>
</cfif>
</cffunction>
<cffunction name="getPassword" access="public" returntype="string" output="false">
<cfreturn variables.instance.password />
</cffunction>
<!--- MOMENTO --->
<cffunction name="setMomento" access="public" returntype="void" output="false">
<cfargument name="momento" type="struct" required="true" />
<cfset variables.instance = arguments.momento>
</cffunction>
<cffunction name="getMomento" access="public" returntype="struct" output="false">
<cfreturn variables.instance />
</cffunction>
Cheers,
Aaron Greenlee
My Site
ColdBox Development Best Practices
Related
I have to create a web service in ColdFusion. I have tried the below 2 ways. Can anyone help me to find which one is the best way (Both Performance and security enhancement basis)
First Way
Created a cfm page like below;
<cfset result = StructNew() />
<cfset resultStruct = StructNew() />
<cfset validStruct = StructNew() />
<cfset VARIABLES.Sample = CreateObject("component","main.webservice.Sample")>
<cfif NOT isDefined("URL.method")>
<cfset result['status'] = false >
<cfset result['message'] = 'method is missing' />
<cfoutput>#SerializeJSON(result)#</cfoutput>
<cfabort>
</cfif>
<cfswitch expression="#URL.method#">
<cfcase value="get">
<cfset fieldList = "name">
<cfset validStruct = validate(fieldList) />
<cfif validStruct['status']>
<cfset resultStruct = VARIABLES.Sample.get(argumentCollection=URL) />
</cfif>
<cfoutput>#SerializeJSON(resultStruct)#</cfoutput>
<cfbreak>
</cfcase>
<cfcase value="put">
<cfset fieldList = "name,value">
<cfset validStruct = validate(fieldList) />
<cfif validStruct['status']>
<cfset resultStruct = VARIABLES.Sample.put(argumentCollection=URL) />
</cfif>
<cfoutput>#SerializeJSON(resultStruct)#</cfoutput>
<cfbreak>
</cfcase>
<cfdefaultcase>
<cfset result['status'] = false >
<cfset result['message'] = 'Not a valid method' />
<cfoutput>#SerializeJSON(result)#</cfoutput>
<cfbreak>
</cfdefaultcase>
</cfswitch>
And Created a cfc named 'Sample' under webservice folder and called like above.
WebService URL
http://test.com/webservice/Sample.cfm?method=get&name=test
Second Way
Called directly from the CFC Sample
Sample.CFC
<cfcomponent displayname="Sample" hint="Sample WebService" output="false">
<cffunction name="get" access="remote" returntype="struct" returnformat="json">
<cfargument name="name" required="true" type="string" >
<cfreturn StructNew() />
</cffunction>
<cffunction name="put" access="remote" returntype="struct" returnformat="json">
<cfargument name="name" required="true" type="string" >
<cfargument name="value" required="true" type="string" >
<cfreturn StructNew() />
</cffunction>
</cfcomponent>
WebService URL
http://test.com/webservice/Sample.CFC?method=get&name=test
The second method is the standard way to do WebServices in CFML. Along with the functionality, you are seeking you get standards based WSDL returns and definitions. It's a case of rebuilding the wheel. I'm sure the underlying CF code for ws could be optimized, but it's pretty good as is and has been field-tested by millions.
I would suggest setting up RESTful web services in ColdFusion. Here is an excellent article to get you started.
There's also Taffy which claims to make it simpler, although I have not used it.
I am trying to write a session helper and facing to problem to test if a Struct key in session exists?
I am trying like
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="Any" />
<cfreturn Evaluate( "StructKeyExists( Session, #Arguments.Key# )" ) />
</cffunction>
Where I am calling the function like
<cfif Exists("data.fromdate") >
...
</cfif>
How should I write it?
Thanks
if you are checking to see if key "Test" exists in the session struct, try something like this:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn StructKeyExists(session, arguments.Key) />
</cffunction>
<cfif Exists("Test") >
....
</cfif>
Another concept, or two, since you are looking for a struct within the session would be:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, listFirst(arguments.Key,"."))
AND structKeyExists(session[listFirst(arguments.Key,".")], listLast(arguments.Key, "."))) />
</cffunction>
<cfif Exists("data.Test") >
....
</cfif>
and
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="struct" required="true" type="String" />
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, arguments.struct)
AND structKeyExists(session[arguments.struct], arguments.key)) />
</cffunction>
<cfif Exists("data", "Test") >
....
</cfif>
Hope all this helps point you in the right direction, good luck!
The following code will check any depth struct, and also correctly locks the Session scope.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cfset local.mainKeyList = ListChangeDelims(ListDeleteAt(Arguments.Key, ListLen(Arguments.Key, "."), "."), ",", ".")>
<cfset local.StructChain = "Session">
<cfloop list="#local.mainKeyList#" index="local.CurrentKey">
<cfset local.StructChain &= '["#local.CurrentKey#"]'>
</cfloop>
<cflock scope="session" type="readonly" timeout="3">
<cftry>
<cfset local.Exists = StructKeyExists(Evaluate(local.StructChain), ListLast(Arguments.Key, "."))>
<cfcatch>
<cfset local.Exists = false>
</cfcatch>
</cftry>
</cflock>
<cfreturn local.Exists>
</cffunction>
<cflock scope="session" type="exclusive" timeout="3">
<cfset Session.data.log.deep = "I'm here!">
</cflock>
<cfoutput>#Exists("data.log.deep")#</cfoutput>
Hopefully the amount of code in this function will justify why a helper function would be useful, to those pondering your reasons. This doesn't currently, but could be enhanced to, deal with Structs inside of Arrays as well. This also doesn't deal with an empty Arguments.Key, or fail gracefully on a cflock timeout, but should get you started.
Additionally, those that want to comment that cflock isn't required, please read the ColdFusion cflock docs first.
Simplified, but may provide inaccurate results in extremely rare conditions
Doing an IsDefined inline in your code will provide the opportunity for false positives, however having the IsDefined inside a udf or cfc method reduces this risk greatly to the point it may not need be a consideration. If you're happy to take that chance then you can simplify the function using IsDefined as Peter Boughton suggests.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cflock scope="session" type="readonly" timeout="3">
<cfset local.Exists = IsDefined("Session." & Arguments.Key)>
</cflock>
<cfreturn local.Exists>
</cffunction>
As Al Everett mentioned above, I don't remember the last time I had an app that didn't have session enabled. I guess if you can't be sure of that, then it makes sense to see if Session exists. My code for this would include:
<!--- in the application.cfc --->
<cffunction name="onSessionStart" output="false">
<!--- default session structure, you can also add default values to the data
structure here to ensure they exist later --->
<cfset session.data = {} />
</cffunction>
<!--- then in code use structKeyExists instead of a whole new function --->
<cfif structKeyExists(session.data, myKey)>
<!--- if you really wanted the "exists" function --->
<cffunction name="dataKeyExists" returntype="boolean" output="false">
<cfargument name="key" required="true" />
<cfreturn structKeyExists(session.data, arguments.key) />
</cffunction>
Depending on what's going on, I might choose to pass in the session to maintain encapsulation. But it doesn't always make sense to be a slave to OO and introduce complexity just for the sake of maintaining a pattern. Passing in the session structure and evaluating the key is really just a big workaround to using the "structKeyExists" function.
I also dislike having a function called "exists" because it tells me nothing about what it's really evaluating. I'd assume a function like that was like "isDefined" and more generic than just testing for a key in a specific structure.
<cfif structkeyexists(session, "data") and structkeyexists(session["data"], key)>
...
</cfif>
Why not just call <cfif isNull(session.data.fromdate)>
If the key data does not exist in session it will not throw, just returns false.
I am trying to build a web service. Here is my code for a simple web service which returns a string.
At the beginning i inserted some code from ben nadel
It refreshes the stubfile automatically because otherwise you get errors while passing parameters.
<cfcomponent
displayname="BaseWebService"
output = "false"
hint="This handles core web service features">
<cffunction
name="Init"
access="public"
returntype="any"
output="false"
hint="Returns an initialized web service instance.">
<cfreturn THIS />
</cffunction>
<cffunction
name="RebuildStubFile"
access="remote"
returntype="void"
output="false"
hint="Rebuilds the WSDL file at the given url.">
<cfargument name="Password" type="string" required="true" default="" />
<cfif NOT Compare(ARGUMENTS.Password, "sweetlegs!")>
<cfset CreateObject("java", "coldfusion.server.ServiceFactory"
).XmlRpcService.RefreshWebService(
GetPageContext().GetRequest().GetRequestUrl().Append("?wsdl").ToString()) />
</cfif>
<cfreturn />
</cffunction>
<cffunction
name="easyService"
access="remote"
returntype="any"
output="false">
<cfargument name="anyOutput" type="string" default="this and that" />
<cfargument name="xtype" type="string" required="yes" default="1" />
<cfif Compare(xtype, "1") EQ 0>
<cfset anyVar = "one" />
<cfelse>
<cfset anyVar = "two" />
</cfif>
<cfreturn anyVar>
</cffunction>
</cfcomponent>
Here I am trying to invoke the webservice.
<cfinvoke
webservice="https://[...]/Components/Webservice.cfc?wsdl"
method="RebuildStubFile">
<cfinvokeargument
name="Password"
value="sweetlegs!" />
</cfinvoke>
<cfinvoke
webservice="[...]/Components/Webservice.cfc?wsdl"
method="easyService"
returnVariable="anyVar" >
<cfinvokeargument
name="xtype"
value="2"
omit="true">
</cfinvoke>
<cfdump var="#anyVar#">
The first method of my web service component can be invoked but the second one always returns this error message:
coldfusion.xml.rpc.ServiceProxy$ServiceMethodNotFoundException: Web service operation easyService with parameters {xtype={2}} cannot be found.
at coldfusion.xml.rpc.ServiceProxy.invoke(ServiceProxy.java:149)
at coldfusion.runtime.CfJspPage._invoke(CfJspPage.java:2301)
at coldfusion.tagext.lang.InvokeTag.doEndTag(InvokeTag.java:454)
If i type in the url of the webservice, by adding
?method=easyService&xtype=2
it returns the right value. but this is like passing values with a GET method.
i have been searching for hours and don't know where the problem occures.
I think when using WebService call you need to specify all arguments and use omit="true" on the proper one (not on xtype).
<cfinvoke
webservice="[...]/Components/Webservice.cfc?wsdl"
method="easyService"
returnVariable="anyVar" >
<cfinvokeargument
name="anyOutput"
value=""
omit="true">
<cfinvokeargument
name="xtype"
value="2">
</cfinvoke>
I am trying to convert some pages from my app to use cfc's, and one page uses a stored procedure to retrieve a couple sets of data.
Now when I access the results, they act just like a if I used a <cfquery> tag, and all of the functionality that gives. So now I am trying to use this same stored procedure in a cfc that I am building, and I would like to be able access the results in the same manner, and there in lies my problem. I'm not sure how to return multiple queries from the function, without creating an array, which I have started. By the way, the function is incomplete. I was just trying to get something to work. In the below setup I get an array of query objects, but I feel there is a better way to do it.
Here is the <cffuntion>:
<cffunction name="getProfileData"
access="public"
output="false"
returntype="string">
<cfargument name="cusip" type="string" required="true">
<cfargument name="report_date" type="date" required="true">
<cfset var errorMessage = "everything is good">
<cftry>
<cfstoredproc datasource="#dsn#" procedure="prc_asset_profile_retrieve">
<cfprocparam type="in" cfsqltype="cf_sql_varchar" value="#cusip#" dbvarname="#cusip">
<cfprocparam type="in" cfsqltype="cf_sql_varchar" value="#report_date#" dbvarname="#reportDate">
<cfprocresult name="profile_head" resultset="1">
<cfprocresult name="attribution" resultset="2">
<cfprocresult name="characteristics" resultset="3">
<cfprocresult name="exposure" resultset="4">
<cfprocresult name="weights" resultset="5">
<cfprocresult name="holdings" resultset="6">
</cfstoredproc>
<cfset var profileArray = []>
<cfset #ArrayAppend(profileArray,profile_head)#>
<cfcatch type="any">
<cfset errorMessage = "something happened">
</cfcatch>
</cftry>
<cfreturn profileArray>
</cffunction>
When I output some test data, it matches up
<cfset count = fund_profile.getProfileData("#cusip#","#report_date#")>
<cfdump var="#count[1]#">
<cfoutput>
From cfc (##count[1].recordCount##): #count[1].recordCount#<br>
From stored proc (##profile_head.recordCount##): #profile_head.recordCount#
</cfoutput>
I get:
From cfc (#count[1].recordCount#): 1
From stored proc (#profile_head.recordCount#): 1
But the second way looks so much cleaner.
-----------------------------WORKING SOLUTION------------------------------
So after working with the answer from #leigh, I came up with this.
Here is the full cfc:
<cfcomponent displayname="Fund Profile" hint="This is the cfc that will do the processing of all fund profile information" output="false">
<cfproperty name = "result1"> <!--- PROFILE HEAD --->
<cfproperty name = "result2"> <!--- ATTRIBUTION --->
<cfproperty name = "result3"> <!--- CHARACTERISTICS --->
<cfproperty name = "result4"> <!--- EXPOSURE --->
<cfproperty name = "result5"> <!--- WEIGHTS --->
<cfproperty name = "result6"> <!--- HOLDINGS --->
<cffunction name="init"
displayname="init"
hint="This will initialize the object"
access="public"
output="false"
returnType="Any">
<cfargument name="dsn" type="string" required="true" />
<cfargument name="cusip" type="string" required="true" />
<cfargument name="report_date" type="date" required="true" />
<cfset variables.dsn = #arguments.dsn#>
<cfset variables.cusip = #arguments.cusip#>
<cfset variables.report_date = #arguments.report_date#>
<cfscript>
getProfiledata(cusip,report_date);
</cfscript>
<cfreturn this>
</cffunction>
<cffunction name="getProfileData"
access="private"
output="false"
returntype="void">
<cfargument name="cusip" type="string" required="true">
<cfargument name="report_date" type="date" required="true">
<cfstoredproc datasource="#dsn#" procedure="prc_asset_profile_retrieve">
<!--- STORED PROCEDURE HASN'T CHANGED. SEE ABOVE FOR CODE --->
</cfstoredproc>
<cfscript>
setProfilehead(profile_head);
setAttribution(attribution);
setCharacteristics(characteristics);
setExposure(exposure);
setWeights(weights);
setHoldings(holdings);
</cfscript>
<cfreturn>
</cffunction>
<!--- NOT GOING TO INCLUDE ALL SETTERS AND GETTERS, --->
<!--- BECAUSE THEY ARE ALL THE SAME OTHER THAN THE NAMES --->
<cffunction name="setProfileHead" access="private">
<cfargument name="ProfileHead">
<cfset variables.result1 = arguments.ProfileHead>
</cffunction>
<cffunction name="getProfileHead" access="public" returntype="query">
<cfreturn variables.result1>
</cffunction>
</cfcomponent>
Here is the code from the calling page:
<cfset fund_profile = CreateObject("component", "CFCs.fund_profile").init("#dsn#","#cusip#","#report_date#")>
<cfset profile_head = fund_profile.getProfileHead()>
Sorry for all the code, but I wanted to make the code available. So does anyone see any problems with what I came up with?
A function can only return a single value. If you wish to return multiple values, you will need to use some type of complex object (an array, structure, ...) If arrays are not intuitive enough, you could place the queries in a structure and return that instead. Then the calling page could access the queries by name, rather than index.
(Side note, be sure to properly var scope/localize all function variables.)
<cfset var data = {}>
...
<!--- store query results in structure --->
<cfset data.profile_head = profile_head>
<cfset data.attribution = attribution>
...
<cfset data.holdings = holdings>
<!--- return structure --->
<cfreturn data>
I would create other methods in the CFC that would each be responsible for returning a result from the stored proc. In the main method , call setters
setProfileHead(profilehead:profileHead)
<cffunction name=ProfileHead>
<cfarguments name=ProfileHead />
<cfset variables.profilehead = arguments.profilehead>
</cffunction>
Then...
<cffunction name=GetProfileHead>
<cfreturn variables.profileHead />
</cffuction>
Is there a recommended (and preferably free) way in ColdFusion to access a remote file that is protected by NTLM authentication? The cfhttp tag appears to only support Basic authentication.
This CFX Tag - CFX_HTTP5 - should do what you need. It does cost $50, but perhaps it's worth the cost? Seems like a small price to pay.
Here is some code I found in:
http://www.bpurcell.org/downloads/presentations/securing_cfapps_examples.zip
There are also examples for ldap, webservices, and more.. I'll paste 2 files here so you can have an idea, code looks like it should still work.
<cfapplication name="example2" sessionmanagement="Yes" loginStorage="Session">
<!-- Application.cfm -->
<!-- CFMX will check for authentication with each page request. -->
<cfset Request.myDomain="allaire">
<cfif isdefined("url.logout")>
<CFLOGOUT>
</cfif>
<cflogin>
<cfif not IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<!--Invoke NTSecurity CFC -->
<cfinvoke component = "NTSecurity" method = "authenticateAndGetGroups"
returnVariable = "userRoles" domain = "#Request.myDomain#"
userid = "#cflogin.name#" passwd = "#cflogin.password#">
<cfif userRoles NEQ "">
<cfloginuser name = "#cflogin.name#" password = "#cflogin.password#" roles="#stripSpacesfromList(userRoles)#">
<cfset session.displayroles=stripSpacesfromList(userRoles)><!--- for displaying roles only --->
<cfelse>
<cfset loginmessage="Invalid Login">
<cfinclude template="loginform.cfm">
<cfabort>
</cfif>
</cfif>
</cflogin>
<!-- strips leading & trailing spaces from the list of roles that was returned -->
<cffunction name="stripSpacesfromList">
<cfargument name="myList">
<cfset myArray=listtoarray(arguments.myList)>
<cfloop index="i" from="1" to="#arraylen(myArray)#" step="1">
<!--- <cfset myArray[i]=replace(trim(myArray[i]), " ", "_")>
out<br>--->
<cfset myArray[i]=trim(myArray[i])>
</cfloop>
<cfset newList=arrayToList(myArray)>
<cfreturn newList>
</cffunction>
This is the cfc that might be of interest to you:
<!---
This component implements methods for use for NT Authentication and Authorization.
$Log: NTSecurity.cfc,v $
Revision 1.1 2002/03/08 22:40:41 jking
Revision 1.2 2002/06/26 22:46 Brandon Purcell
component for authentication and authorization
--->
<cfcomponent name="NTSecurity" >
<!--- Authenticates the user and outputs true on success and false on failure. --->
<cffunction name="authenticateUser" access="REMOTE" output="no" static="yes" hint="Authenticates the user." returntype="boolean">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
ntauth.authenticateUser(arguments.userid, arguments.passwd);
</cfscript>
<cfreturn true>
<cfcatch>
<cfreturn false>
</cfcatch>
</cftry>
</cffunction>
<!---
Authenticates the user and outputs true on success and false on failure.
--->
<cffunction access="remote" name="getUserGroups" output="false" returntype="string" hint="Gets user groups." static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now???
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cflog text="Error in ntsecurity.cfc method getUserGroups - Error: #cfcatch.message#" type="Error" log="authentication" file="authentication" thread="yes" date="yes" time="yes" application="no">
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
<!---
This method combines the functionality of authenticateUser and getUserGroups.
--->
<cffunction access="remote" name="authenticateAndGetGroups" output="false" returntype="string" hint="Authenticates the user and gets user groups if it returns nothing the user is not authticated" static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
// so we don't have anything specific here
ntauth.authenticateUser(arguments.userid, arguments.passwd);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
If the code from Brandon Purcell that uses the jrun.security.NTauth class doesn't work for you in cf9 (it didn't for me) the fix is to use the coldfusion.security.NTAuthentication class instead. Everything worked fine for me.
You could try following the guidance here: http://cfsilence.com/blog/client/index.cfm/2008/3/17/ColdFusionSharepoint-Integration--Part-1--Authenticating
Here is what it boils down to you doing:
edit the client-config.wsdd
Change
<transport
name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender">
</transport>
to
<transport
name="http"
pivot="java:org.apache.axis.transport.http.CommonsHTTPSender">
</transport>
In my case I fixed this problem using 'NTLM Authorization Proxy Server'
http://www.tldp.org/HOWTO/Web-Browsing-Behind-ISA-Server-HOWTO-4.html
work fine for me :)