ColdFusion infinite loop causes Java heap space error

If you get an error page like this, and are scratching your head as to why, it's probably an infinite loop in your CFML code. The error I had was this, and sure enough, I had an out of control loop.

500

ROOT CAUSE:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2882)
at java.io.CharArrayWriter.write(CharArrayWriter.java:105)
at coldfusion.runtime.CharBuffer.replace(CharBuffer.java:37)
at coldfusion.runtime.CharBuffer.replace(CharBuffer.java:50)
at
coldfusion.runtime.NeoBodyContent.write(NeoBodyContent.java:254)
at.........

Putting ColdFusion to sleep

Here is a code snippet that makes the ColdFusion processing "sleep" for the specified number of milliseconds. This works on ColdFusion MX 6 and above, which can expose the Java language from within CFML.

<cfset thread = CreateObject("java", "java.lang.Thread")>
<cfset thread.sleep(3000)> <!--- About to sleep for 3 seconds... --->

ColdFusion 8 introduced a new sleep() function. The above code and the new function are explained in more detail in this ColdFusion Cookbook article.

Generating an iCalendar .ics file using ColdFusion

I've been working on a small project at work to allow a user to click a link from an event registration confirmation email, which will open a .ics file in the browser. This special file is in the iCalendar format, and is recognized by MS Outlook, Mozilla Sunbird, and other calendaring tools. It creates an entry in your calendar, with a 30 minute reminder alert, to help you remember to attend the webinar event you registered for. I learned from the vCal() function on cflib.org, and will be submitting my new iCalUS() UDF soon. But here is the code now, as it takes some time to get verified for inclusion on the CFLib.org site.

Download the code in a zip file.

I wrote the function to work in the U.S. and account for daylight savings time. Hopefully developers outside the U.S. can adapt this code to fit their timezones accordingly. Here is the code used for the test submission form and cfcontent/cfheader tags for the following demo.

Change any field(s) below and submit to generate a calendar file: <b>newAppointment.ics</b>
<P>
<cfoutput>
<form method="post">
<table>
<tr>
   <td align="right">Organizer name</td>
   <td><input type="Text" name="on" value="#Form.on#" size="30"></td>
</tr>
<tr>
   <td align="right">Organizer email</td>
   <td><input type="Text" name="oe" value="#Form.oe#" size="30"></td>
</tr>
<tr>
   <td align="right">Description</td>
   <td><input type="Text" name="desc" value="#Form.desc#" size="60"> (use \n sequences for newlines)</td>
</tr>
<tr>
   <td align="right">Subject</td>
   <td><input type="Text" name="sub" value="#Form.sub#" size="30"></td>
</tr>
<tr>
   <td align="right">Location</td>
   <td><input type="Text" name="loc" value="#Form.loc#" size="30"></td>
</tr>
<tr>
   <td align="right">Start Date/Time</td>
   <td><input type="Text" name="st" value="#Form.st#" size="20"> (format: <b>m/d/yyyy HH:mm</b> OR <b>h:mm TT</b> -- this is Eastern time)</td>
</tr>
<tr>
   <td align="right">End Date/Time</td>
   <td><input type="Text" name="et" value="#Form.et#" size="20"> (format: <b>m/d/yyyy HH:mm</b> OR <b>h:mm TT</b> -- this is Eastern time)</td>
</tr>
</table>
<input type="Submit" name="Submit" value="Submit">
</form>
</cfoutput>

<cfif IsDefined("Form.Submit")>
   <cfset eventStr = StructNew()>
   <cfset eventStr.organizerName = Form.on>
   <cfset eventStr.organizerEmail = Form.oe>   
   <cfset eventStr.startTime = ParseDateTime(Form.st)>
   <cfset eventStr.endTime = ParseDateTime(Form.et)>
   <cfset eventStr.subject = Form.sub>
   <cfset eventStr.location = Form.loc>
   <cfset eventStr.description = Form.desc>
   <cfcontent type="text/calendar" reset="Yes">
   <cfheader name="Content-Disposition" value="inline; filename=newAppointment.ics"><cfoutput>#iCalUS(eventStr)#</cfoutput>
</cfif>

Here is a demo of this in action.

-- Update 4/10/08: I submitted the UDF to cflib.org today. Hopefully Ray will post it soon. --

Using ColdFusion and RegEx on a special file naming convention

I had a project where we had a graphics library, and a bunch of zip files were placed in a directory. The zip files contained 1 or more images packaged up. It was mostly used for product shots to show views of front, back, left, or right. Each zip file could have an associated thumbnail preview image. The files followed a special naming convention, with file names in a format of: SUBJ_DESC_VIEW_FORMAT_TYPE.zip. I used a RegEx (regular expression), as well as the Find() function to parse the file name.

SUBJ is the subject, and should describe the file, and helps order the files alphabetically in the directory.

DESC is the description, such as: LOGO, Model, Version-3, etc. (hint: you can lengthen the description with up to 3 dashes -'s)

VIEW is optional, and can be either: Ft (front), Rt (right), Lt (left), or Bk (back)

FORMAT can be either: PPT, PRINT, or WEB

TYPE is optional, and can be either: EPS, JPG, TIF

A thumbnail preview can be used, and must be named: SUBJ_DESC_VIEW_thumb.gif (or .jpg). If VIEW was used for the zip file name, it must also be used in the thumbnail file name.

Example zip file: UTM_1100D_Ft_PRINT_EPS.zip

Example thumb file: UTM_1100D_Ft_thumb.gif

Here was the code I used to parse the file name and display a friendly version without dashes to the user.

<cfsavecontent variable="file_desc">
<cfset found = REFind("\_[[:alnum:]]+\-*[[:alnum:]]*\-*[[:alnum:]]*\-*[[:alnum:]]*\-*[[:alnum:]]*\-*[[:alnum:]]*\_",name,0,"TRUE")>

<!--- grab the description out of the file name, replacing dashes with spaces --->
<cfif found.pos[1]>#Replace(Mid(name,found.pos[1]+1,found.len[1]-2),"-"," ","ALL")#</cfif>

<!--- tell user which view --->
<cfif FindNoCase("_Ft",name,1)>
   (Front view)
<cfelseif FindNoCase("_Rt",name,1)>
   (Right view)
<cfelseif FindNoCase("_Lt",name,1)>
   (Left view)
<cfelseif FindNoCase("_Bk",name,1)>
   (Back view)
</cfif>

<!--- tell user what file type(s) --->
<cfif Find("_EPS",name,1)>
   (EPS High-Res)
<cfelseif Find("_JPG",name,1)>
   (JPG High-Res)
<cfelseif Find("_TIF",name,1)>
   (TIFF High-Res)
<cfelseif Find("_PPT",name,1)>
   (PowerPoint)
<cfelseif Find("_WEB",name,1)>
   (WEB Low-Res)
<cfelseif Find("_PRINT",name,1)>
   (PRINT High-Res)
</cfif>
</cfsavecontent>
<cfif Not Len(Trim(file_desc))>
   File: #name#
<cfelse>
   #file_desc#
</cfif>
Here is an example of what the parsing accomplished.

Example zip file: UTM_Model-1100D-Silver_Ft_PRINT_EPS.zip

The user would see: Model 1100D Silver (Front view) (EPS High-Res)

ColdFusion CFDIRECTORY fun with sorting

Last week on our CFUG's technical email list, a question was asked by @cosmic: I have created a dynamically generated XML based off of the contents of a directory using CFDIRECTORY. The problem I am having is that when it outputs the XML it doesn't put the files in the correct order that I want. It sorts them as 1.jpg, 10.jpg, 11.jpg,12.jpg, 13.jpg, 14.jpg, 15.jpg ,16.jpg, 17.jpg,18.jpg, 19.jpg, 2.jpg, 20.jpg and so on. I want them to sort as 1.jpg ,2.jpg, 3.jpg, 4.jpg, 5.jpg, 6.jpg. The only fix I have run into is to add zeros on to the beginning of the files 01.jpg, 02.jpg. Is there a way around this so I don't have to add zero to my 1,000 files?

An answer was quickly given by @lockjw: Use QueryAddColumn to add a sorting column the the CFDIRECTORY result. Parse the file name to get the numeric value - put that into the new column. Use query of query to output results, sorting on the newly added column.

However, @cosmic was still stuck and asked for some code. So I did what @lockjw explained, but with a directory of 14 text files named 1.txt thru 14.txt. It worked great...

<cfdirectory action="LIST" directory="#expandpath('.')#" name="dirlist" filter="*.txt" sort="name">
<cfdump var="#dirlist#">
<cfset queryaddcolumn(dirlist,"mysort",ArrayNew(1))>
<cfloop query="dirlist">
<cfset num = ListGetAt(name,1,".")>
<cfset querysetcell(dirlist,"mysort",num,currentrow)>
</cfloop>
<cfdump var="#dirlist#">
<cfquery name="dirlist_sorted" dbtype="query">
select *
from dirlist
order by mysort
</cfquery>
<cfdump var="#dirlist_sorted#">

Blog.CFC is up and running

It took some struggles with datasource setup with my new hosting provider gisol.com, but I'm finally up and running. I found a bug along the way. In the "blog.ini.cfm" file, there cannot be any whitespace after the value for "dsn=". Apparently, I had a space, and it kept throwing a Data source not found error. Ray needs to trim this value and avoid an easy gotcha for a newbie installer.

I'll probably add some CF related posts I made in the past few years on my personal blog www.pullis.org/blog and backdate them accordingly.

Speedy CSV file parsing using ColdFusion

A client of mine needed a solution to bulk import CSV files of affiliate coupon data into his database. I found a great blog by Ben Nadel who covered the exact topic I was looking for: CSVToArray() ColdFusion UDF For Parsing CSV Data / Files

After I implemented Ben's function, we were able to import 1000 records in about 1.6 seconds. Not bad, considering it used to take him hours of time to manually input the coupons one at a time.

Thanks Ben (and Steven Levithan who helped improve the RegEx)

Using ColdFusion to create a Lead in SalesForce using SOAP

At my day job, Secure Computing, I needed to figure out how to create a new Lead in SalesForce from a partner deal registration web application. I already had experience using Web-to-lead (WTL), but this would not work for the type of Lead I was trying to create. In this case, the Lead had fields for a Contact and Account (both lookup fields), which WTL doesn't support.

I did some google searching for ColdFusion web services and SalesForce and found myself at the Adobe forums. After reading all the posts and grabbing some sample code, I started to figure it out. After a few days of coding and testing using SOAP web services, I had my solution. I posted my findings back to the Adobe forum to give back to the community, and my submission is found here on page 3 (posted by "tccfug"). The only drawback is I wasn't able to associate the Lead to a Campaign. However, it wasn't a show stopper and my solution is now in production.

Here's the code, hope it will help somebody else down the road... Make sure you change the first lines of code with your respective username and password to login to SalesForce. This is required to first begin a new session, then create the lead with the sessionid.

<cfsetting showdebugoutput="No">
<cfset UserName = "myemail@mydomain.com">
<cfset Pwd = "mypassword">
<cfset loginurl = "https://www.salesforce.com/services/Soap/u/9.0">

<!---
LOGIN TO SALESFORCE TO START A NEW SESSION
--->

<cfoutput>
<cfsavecontent variable = "LoginSOAP"><?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<SOAP-ENV:Header>
<m:LoginScopeHeader xmlns:m="urn:partner.soap.sforce.com"> <m:organizationId></m:organizationId>
</m:LoginScopeHeader>
<m:CallOptions xmlns:m="urn:partner.soap.sforce.com">
<m:client></m:client>
</m:CallOptions>
</SOAP-ENV:Header>
<SOAP-ENV:Body><!---Body of Soap--->
<m:login xmlns:m="urn:partner.soap.sforce.com">
<m:username>#UserName#</m:username><!---User Name for login--->
<m:password>#Pwd#</m:password><!---Password for Login--->
</m:login>
</SOAP-ENV:Body><!---end of the body--->
</SOAP-ENV:Envelope></cfsavecontent><!---End of the Login SOAP--->
</cfoutput>
<cfhttp url="#loginurl#" method="post"><!---Variables to be posted at this URL --->
<cfheader name="Content-Type" value="text/xml; charset=utf-8" />
<cfhttpparam type="xml" value="#LoginSOAP#" />
<cfhttpparam type="header" name="SOAPAction" value="login" /><!---method of the web service--->
</cfhttp>
<!--- the following parses out the ServerURL and the SessionID which will be used in the 2nd SOAP request to generate a Lead --->
<cfset serurl_start = Find("<serverUrl>",cfhttp.FileContent)>
<cfset serurl_end = Find("</serverUrl>",cfhttp.FileContent)>
<cfset serurl_final = Trim(Mid(cfhttp.FileContent,serurl_start+11,serurl_end-(serurl_start+11)))>
<cfset sesid_start = Find("<sessionId>",cfhttp.FileContent)>
<cfset sesid_end = Find("</sessionId>",cfhttp.FileContent)>
<cfset sesid_final = Trim(Mid(cfhttp.FileContent,sesid_start+11,sesid_end-(sesid_start+11)))>



<!---
LEAD SUBMISSION WHICH NEEDS TO USE SESSION FROM LOGIN ABOVE
--->

<cfoutput>
<cfsavecontent variable="LeadSoap"><?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soapenv:Header>
<ns1:SessionHeader soapenv:mustUnderstand="0" xmlns:ns1="urn:enterprise.soap.sforce.com">
<ns2:sessionId xmlns:ns2="urn:enterprise.soap.sforce.com">#sesid_final#</ns2:sessionId>
</ns1:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<create xmlns="urn:enterprise.soap.sforce.com">
<sObjects xsi:type="ns3:Lead" xmlns:ns3="urn:sobject.enterprise.soap.sforce.com">
<ns3:RecordTypeId>01250000000DKxf</ns3:RecordTypeId> <!--- hardcoded for Prospects --->
<ns3:FirstName>Rich</ns3:FirstName>
<ns3:LastName>Dude</ns3:LastName>
<ns3:Title>CEO</ns3:Title>
<ns3:Email>rich_dude@prospect.com</ns3:Email>
<ns3:Company>TEST</ns3:Company>
<ns3:Street>123 Money Lane</ns3:Street>
<ns3:City>Las Vegas</ns3:City>
<ns3:State>NV</ns3:State>
<ns3:Country>US</ns3:Country>
<ns3:PostalCode>89109</ns3:PostalCode>
<ns3:Phone>888-PHONE</ns3:Phone>
<ns3:Fax>777-FAX</ns3:Fax>
<ns3:LeadSource>Other</ns3:LeadSource>
<ns3:OwnerId>00550000000wtO9</ns3:OwnerId><!--- CFID of contact --->
<!--- And any other fields
See http://www.sforce.com/resources/api.jsp for SOAP Message examples
See http://www.sforce.com for documentation on the fields you can send. --->

</sObjects>
</create>
</soapenv:Body>
</soapenv:Envelope></cfsavecontent>
</cfoutput>

<cfhttp url="#serurl_final#" method="POST">
<cfhttpparam type="HEADER" name="Content-Type" value="text/xml; charset=utf-8">
<cfhttpparam type="HEADER" name="Accept" value="application/soap+xml, application/dime, multipart/related, text/*">
<cfhttpparam type="HEADER" name="User-Agent" value="Axis/1.1">
<cfhttpparam type="HEADER" name="Host" value="na1.salesforce.com">
<cfhttpparam type="HEADER" name="Cache-Control" value="no-cache">
<cfhttpparam type="HEADER" name="Pragma" value="no-cache">
<cfhttpparam type="HEADER" name="Version" value="HTTP/1.0">
<cfhttpparam type="HEADER" name="SOAPAction" value="update">
<cfhttpparam type="HEADER" name="Content-Length" value="#len(trim(LeadSoap))#">
<cfhttpparam type="BODY" value="#trim(LeadSoap)#">
</cfhttp>

<cfset faultcode_start = Find("<faultcode>",cfhttp.FileContent)>
<cfset success_start = Find("<success>",cfhttp.FileContent)>
<cfcontent type="text/html" reset="Yes">
<cfif success_start>
   <cfset leadid_start = Find("<id>",cfhttp.FileContent)>
   <cfset leadid_end = Find("</id>",cfhttp.FileContent)>
   <cfset leadid_final = Trim(Mid(cfhttp.FileContent,leadid_start+4,leadid_end-(leadid_start+4)))>
   <cfoutput>
   <b>Lead ID: <a href="https://na3.salesforce.com/#Left(leadid_final,15)#" target="_blank">#Left(leadid_final,15)#</a></b>
   </cfoutput>

<cfelseif faultcode_start>
   <cfset faultcode_end = Find("</faultcode>",cfhttp.FileContent)>
   <cfset faultcode_final = Trim(Mid(cfhttp.FileContent,faultcode_start+11,faultcode_end-(faultcode_start+11)))>
   <cfset faultstring_start = Find("<faultstring>",cfhttp.FileContent)>
   <cfset faultstring_end = Find("</faultstring>",cfhttp.FileContent)>
   <cfset faultstring_final = Trim(Mid(cfhttp.FileContent,faultstring_start+13,faultstring_end-(faultstring_start+13)))>
   <cfoutput>
   <b>Fault Code: #faultcode_final#</b><br>
   <b>Fault String: #faultstring_final#</b>
   </cfoutput>

<cfelse>
   <b>Unknown response</b><br>
   <cfoutput>#cfhttp.FileContent#</cfoutput>
</cfif>

Naming a ColdFusion variable beginning with a number

The naming rules for creating ColdFusion variables are found here in the LiveDocs. The first bullet point is

  • A variable name must begin with a letter, underscore, or Unicode currency symbol.
However, I am doing some integration with SalesForce.com, and they have custom variables that are named like "00N30000000dqFd". Now, if I want to name a form variable with that name, and do some validation before posting the form, I was running into problems. Here is some sample code and comments that outline my struggles. If you comment out the 3 spots (lines 3, 8, and 13-15) that throw errors, the code will run and you will get the 3 cfdumps.

<cfset field = "00N30000000dqFd"> <!--- here is a variable that we assign a value starting with a number --->

<!--- <cfset 00N30000000dqFd = "test"> ---> <!--- variable starting with number throws error: "00N30000000dqFd," on line 3, column 8, is not a valid identifer name. --->
<cfparam name="form.#field#" default=""> <!--- paraming "00N30000000dqFd" in the form scope is ok --->
<cfdump var="#form#" label="after param">


<!--- <cfset "form.#field#" = "new value"> ---> <!--- doing this cfset method throws an error: The string "form.00N30000000dqFd" is not a valid ColdFusion variable name. --->
<cfset form["#field#"] = "1st value"> <!--- doing the structure method sets the variable ok --->
<cfdump var="#form#" label="after assigning">


<!--- <cfif IsDefined("form.#field#")> <!--- doing this IsDefined() method of checking if the variable exists in the Form scope throws an error: Parameter 1 of function IsDefined, which is now "form.00N30000000dqFd", must be a syntactically valid variable name.--->
   <cfset "form.#field#" = "2nd value">
</cfif>--->
<cfif StructKeyExists(form,field)> <!--- doing this structure key check method is ok --->
   <cfset form["#field#"] = "2nd value">
</cfif>
<cfdump var="#form#" label="end of demo">

Here is a demo of this in action.

Consuming Flickr RSS feed using ColdFusion

The following code will make a http request for a Flickr RSS feed, and output the results. You may want to cfdump the XMLContent variable to see what other values you can use from the feed. Enjoy...

<cfhttp url="http://api.flickr.com/services/feeds/groups_pool.gne?id=77561358@N00&format=rss_200" method="GET"></cfhttp>
<cfscript>
XMLContent = trim(cfhttp.filecontent);
XMLContent = XMLParse(XMLContent);
</cfscript>
<cfloop from="1" to="#ArrayLen(XMLContent.rss.channel.item)#" index="idx">
<cfoutput>
Link to Flickr: <a href="#XMLContent.rss.channel.item[idx].link.xmlText#">#XMLContent.rss.channel.item[idx].title.xmlText#</a><BR>
Image: <img src='#XMLContent.rss.channel.item[idx]["media:thumbnail"].xmlattributes.url#'><BR>
Author: #XMLContent.rss.channel.item[idx].author.xmlText#<BR>
Date: #XMLContent.rss.channel.item[idx].pubDate.xmlText#
</cfoutput>
<hr>
</cfloop>

Here is a demo of this in action.

More Entries

BlogCFC was created by Raymond Camden. This blog is running version 5.9.002. Contact Blog Owner