devbox@COMPUTEC The Computec development blog

21Jul/100

Coldfusion UDF to create & CHMOD a full directory path

The following problem has come up during a file caching implementation: We've got a directory /var/www/MYCACHE; our filecaching mechanism uses a key-based directory structure to store files there. So let's suppose our key would be 123456789, we'd like to store the file 123456789.cache under /var/www/MYCACHE/123/123456/123456789.cache. This would make sure that no directory needs to hold more than 1,000 nodes.

All would be well if we could be sure that the user jrun (i.e. the user that owns our ColdFusion process) was indeed the only user ever to access this directory structure. In our case we want to be able to access this structure with PHP, too, which runs as mod_php on the webserver, thus as user www-data. To avoid permission problems, we want to assign a permission of 0777 to all directories in the structure upon creation.

7Jul/100

String methods: ColdFusion vs. Java

You may know from previous blog posts that I strongly advise every ColdFusion developer to familiarize himself/herself with the thing that actually makes ColdFusion tick, i.e. with Java. Everybody who writes a single line of CFML should know about the possibilities of extending ColdFusion by directly accessing the underlying Java methods of certain objects. One of the datatypes where actually using Java may make a lot of sense is the string object.

ColdFusion string literals are just plain old Java strings. If you grab a string from e.g. a query object like variables.qMyQuery.myTextColumn, you need to be careful though - even if you think you just have one tuple returned, you've got something other than a string object on your hands. In such a case you need to either specifically target a certain row (like variables.qMyQuery.myTextColumn[1]) or you wrap it up in a JavaCast like Javacast('string',variables.qMyQuery.myTextColumn).

I finally found a moment to actually do some benchmarking on some of the built-in ColdFusion functions against their Java counterparts. This is not a benchmark of Java vs. ColdFusion performance, mind you, it's about deciding whether to use Java-methods inside of ColdFusion vs. ColdFusion's built-in string functions.

18Jun/105

ColdFusion 8 and MySQL 5.1 via JDBC: Help needed! [Solved]

UPDATE: We have now found the cause of the issue. Please scroll to the end of the article for explanation and workaround.

In one of our latest projects we need to access a MySQL 5.1 server (5.1.45) from ColdFusion 8 (8,0,1,195765). Creating the datasource was no problem, the datasource does verify okay - but there obviously is some bug or incompatibility in ColdFusion that causes the connection to be anything but reliable.

28May/101

ColdFusion UDF to get Unix Timestamp from Date

For some legacy MySQL database application I really need Unix timestamps - and I need them in ColdFusion, so MySQL's UNIX_TIMESTAMP just wasn't sufficient for the job. At first I though I could get away with a simple DateDiff - and the result did look plausible. A closer look revealed however that there is probably something fishy going on with DateDiff in ColdFusion. I strongly suspect Daylight Saving Time, though I can't really say at this moment.

20May/100

ColdFusion UDF to generate SEO-friendly URL strings

This function might be convenient if you need to create a seo-friendly URL from a headline that could contain special characters such as German umlauts or accented letters; spaces would be replaced by dashes as recommended by Matt Cutts of Google. Unrecognized characters in a certain Unicode range will finally be replaced by x's, everything that's still not recognized will simply be dropped.

5May/102

Full-text search with ColdFusion using Sphinx

Full text searching is and probably will be for a long time an interesting challenge for any database driven application. Of course ColdFusion already offers a couple of options, though I found most of them somewhat lacking in features or quite complicated to set up.

As we're running mostly on PostgreSQL as database backend, we used to rely solely on the built-in TSearch2 full text search methods of that database. But over the years we have accumulated so much data, some of which is nicely distributed over several tables (the dark side of normalization), that we were really yearning for a less table based and more document focused indexing mechanism - and more speed than TSearch2 could deliver.

Verity never really quite met all of our needs and was a real pain to set up and maintain. CF 9's Solr, which is based on Lucene, might be a mighty step forward, but we're still running on ColdFusion 8, so I really cannot say a lot about handling and performance of the new indexing beast.

For our use cases (i.e. indexing of articles, products in our CMS as well as our forums), Sphinx (for SQL Phrase Index) has shown some amazing results - and we're using it for a couple of months now. In this article I'll show you how to compile, set up and use Sphinx in your ColdFusion application to retrieve search results from documents stored in a PostgreSQL or MySQL database.

3May/101

UDF for RFC822 date

This might be useful if you wish to create RFC-822 type date strings from ColdFusion date variables.GetHttpTimeString() will do something similar, but would always use GMT as timezone. If you want to use the timezone configured on your server, you'll need this:

<cffunction name="rfc822date" output="no" returntype="string">
  <cfargument name="dtDate" type="date" required="no" default="#now()#">
  <cfscript>
   var strReturn = DateFormat(arguments.dtDate, "ddd, dd mmm yyyy");
   strReturn &= TimeFormat(arguments.dtDate, " HH:mm:ss");
   strReturn &= ' ' & NumberFormat(GetTimeZoneInfo().utcHourOffset*-1,'+00');
   strReturn &= NumberFormat(GetTimeZoneInfo().utcMinuteOffset,'00');
   return strReturn;
  </cfscript>
</cffunction>

RFC822 dates are needed in RSS feeds, among others.

16Apr/100

ColdFusion UDF to intersect two lists

Just a quick one: I have a method that takes a list argument; there is a discrete list of legal values for this list. I want to filter the passed argument list by throwing out all the values which are not contained in the list of legal values.

Of course I could use a nested loop to do this - but for longer lists this is neither fast nor elegant. Again I'll turn to Java for this. ColdFusion's arrays are in fact java.util.Lists, so after converting our ColdFusion lists to ColdFusion arrays, we can make use of the Java-API for lists.

Here's a quick UDF that does what I want:

<cffunction name="listIntersect" output="no" returntype="string" 
	hint="returns values from list 1 which are contained in list 2">
	<cfargument name="lstSand" type="string" required="yes" />
	<cfargument name="lstSieve" type="string" required="yes" />
	<cfargument name="chDelimiter" type="string" required="no"
		    default="," />
	<cfscript>
	var aLstSand  = listToArray(arguments.lstSand,arguments.chDelimiter);
	var aLstSieve = listToArray(arguments.lstSieve,arguments.chDelimiter);
	aLstSand.retainAll(aLstSieve);
	return arrayToList(aLstSand,arguments.chDelimiter);
	</cfscript>
</cffunction>

Usage:

<cfset lstSand   = 'foo,bar,illegalparam,whatever' />
<cfset lstSieve  = 'bar,foo,someotherval,whatever' />
<cfset lstSieved = listIntersect(lstSand,lstSieve) />
<cfoutput>#lstSieved#</cfoutput>

This will output foo,bar,whatever.

1Apr/100

Oh shut up, cfmemcached!

Over the last few months, our use of memcached has not so much grown but more like exploded. The cfmemcached project on RIAForge has been a great starter for us. The author is using spymemcached, a very useful memcached client implementation for Java.

As much as I immediately fell in love with cfmemcached as a developer, the admin in me began to be seriously annoyed by the underlying spymemcached's chattyness that was filling up my ColdFusion server log with useless babble about each and every connection it had with the memcached servers:

2010-04-01 14:28:43.569 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.222.80:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, t
oWrite=0, interested=0} to connect queue
2010-04-01 14:28:43.570 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.222.81:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, t
oWrite=0, interested=0} to connect queue
2010-04-01 14:28:43.576 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@5081e9d3
2010-04-01 14:28:43.577 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@11e44f0
2010-04-01 14:28:59.476 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/192.168.222.80:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, t
oWrite=0, interested=0} to connect queue
2010-04-01 17:02:37.723 INFO net.spy.memcached.transcoders.SerializingTranscoder:  Compressed java.lang.String from 20798 to 4387
2010-04-01 17:02:37.731 INFO net.spy.memcached.transcoders.SerializingTranscoder:  Compressed java.lang.String from 55548 to 9819
2010-04-01 17:02:41.866 INFO net.spy.memcached.transcoders.SerializingTranscoder:  Compressed java.lang.String from 391919 to 45429

etc.

After a bit of research I discovered that this beast can be configured to use Log4J and I could thus shut it up quite nicely. All that is necessary are a few additions to our jvm.config and a Log4J-properties-file.

I've got a CF multi-instance install in /opt/jrun4/. I modified the jvm.config in the bin subdirectory of my installation and added the following to the java.args-line:

-Dnet.spy.log.LoggerImpl=net.spy.memcached.compat.log.Log4JLogger -Dlog4j.configuration=file:/opt/jrun4/bin/log4j.properties

(please note that there are no linebreaks in here!)

Then I created the log4j.properties-file in /opt/jrun4/bin/. This contains just two lines so far:

log4j.rootCategory=info
log4j.category.net.spy.memcached=warn

After a restart of the instance, no more chatter. Enjoy the silence!

18Feb/100

The real Y2K problem: LongInt Unix-Timestamps

On January 19th 2038 I'll be 63 years, 9 months and 23 days old. So unfortunately there are still a couple of days until I can think about retirement. What's wrong with this date?

The Unix timestamp of 2038-01-19 03:14:07 is 2147483647. This is the maximum number that fits into the int4 data type. One second later we'll be getting integer overflow for any operations on Unix timestamps. Like getting the actual date from that Unix timestamp via dateAdd() in ColdFusion.