Viewing Category: ColdFusion  [clear category selection]

Perl one-liner for ColdFusion XML configuration file

I wrote a Perl one-liner to modify ColdFusion's adminconfig.xml file to enable the migration wizard using ColdFusion 8 settings. It's somewhat silly, since it's probably every bit as easy to make the change with an editor by hand. However, if you're automating the upgrade of many servers, it could be useful.

ACTION=on for SETTING in runmigrationwizard migratecf8; do perl -p -i -e 'BEGIN{$s=$ENV{"SETTING"}; $a=$ENV{"ACTION"}; %tf=(0,"false",1,"true"); $vs=($a = ~/^on/)?0:1; $vf=($vs eq 0)?1:0; $m="(<$s>)".$tf{$vs}."(</$s>)";} s/$m/\1$tf{$vf}\2/i' adminconfig.xml done

I tried to make it as concise as possible, and there is definitely a shorter way to make the change. However, I wanted to support flipping the values in either direction (on/off). This would conceivable work on any XML file that places simple true/false values in the text node of simple elements. Yes, both of those files! Heh.

PS: I'm posting this on my own blog (which I so rarely do anymore) because I know that Posting all those special characters would have been a complete nightmare on my Posterous blog.

ColdFusion/JRun + Apache Commons Logging

I recently encountered a problem I'd never seen before when taking advantage of powerful Java libraries within CFML components. Since this is really specific to Adobe ColdFusion and Macromedia JRun, it won't be an issue with other configurations. Specifically, here are the details:

  • Microsoft Windows “Server” 2003 Standard Edition
  • Adobe ColdFusion 8.01 Enterprise as MultiServer
  • JavaLoader 1.0 beta
  • jXLS 0.9.9-SNAPSHOT
  • Apache POI 3.5-FINAL
  • Apache Commons BeanUtils 1.8.0
  • Apache Commons BeanUtils Collections 1.8.0
  • Apache Commons BeanUtils Core 1.8.0
  • Apache Commons Collections 3.2.1
  • Apache Commons Digester 1.8
  • Apache Commons JEXL 1.1
  • Apache Commons Logging 1.1.1

The project uses the jXLS XLSTransformer utility class to parse an Excel file and to push information into cells containing syntax like ${bean.prop}. It worked fine on my workstation, but when running on the staging servers, it threw an exception with the following message: User-specified log class 'jrunx.axis.Logging' cannot be found or is not useable.

After many hours of investigation, I tracked the problem down to the so-called discovery process that org.apache.commons.logging.LogFactory uses to provide logger implementations. It was my assumption that when using Mark Mandel's JavaLoader to create instances of classes from the JAR files added to its ClassLoader, they would be isolated from the rest of the JVM. That's not exactly how it works, even if configured not to use ColdFusion's ClassLoader as the parent. To force the LogFactory not to use jrunx.axis.Logging, I tried rebuilding the jXLS library with a commons-logging.properties file to specify which logger implementation to use; I tried adding the properties file to the lib directory. Neither solved the problem.

The solution is pretty simple. After configuring JavaLoader, and before having it instantiate the needed XLSTransformer, just set the desired logger programmatically. Here is the chunk of XML that ColdSpring uses to fill JavaLoader with all the JAR files required.

<bean id="jxlsClassPath" class="model.io.FileEnumerator"> <property name="pathList"> <value>/jxls/lib</value> </property> <property name="patternList"> <value>*.jar</value> </property> </bean> <bean id="jxlsFactory" class="jxls.Factory"> <property name="javaloader"> <bean class="javaloader.JavaLoader"> <constructor-arg name="loadPaths"> <bean factory-bean="jxlsClassPath" factory-method="getFileArray"/> </constructor-arg> </bean> </property> </bean>

The code inside the CFC that does the work of creating the XLSTransformer then explicitly sets the logger:

<cfscript> var javaLoader = getJavaLoader(); var logFactory = "null"; var transformer = createObject("component", "jxls.Transformer").init(); logFactory = javaLoader.create("org.apache.commons.logging.LogFactory").getFactory(); logFactory.setAttribute("org.apache.commons.logging.LogFactory", "org.apache.commons.logging.impl.LogFactoryImpl"); logFactory.setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog"); transformer.setXLSTransformer(getJavaLoader().create("net.sf.jxls.transformer.XLSTransformer")); return transformer; </cfscript>

There was much celebration when this worked, I assure you.

Listening Programs in Windows

While trying to get the line debugger in ColdFusion Builder to work with an installation of ColdFusion 9, I wanted to verify which processes were listening for TCP connections on my Windows XP workstation. I started by using the netstat utility in C:\WINDOWS\system32\ to show the IP and port of each connected endpoint, and the local process identifier. This is useful, but somewhat cumbersome to translate into recognizable application names. Here's a sample of its output:

Proto Local Address Foreign Address State PID TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 3772 TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 1988 TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4 TCP 127.0.0.1:1117 127.0.0.1:4331 ESTABLISHED 3980 TCP 127.0.0.1:1130 0.0.0.0:0 LISTENING 1264 TCP 127.0.0.1:1208 127.0.0.1:20345 ESTABLISHED 640 TCP 127.0.0.1:1217 127.0.0.1:20345 ESTABLISHED 3000 TCP 127.0.0.1:4331 0.0.0.0:0 LISTENING 504

Using the process utility from Cygwin, it's possible to list all of the running processes. It has some quirks when showing Windows information, but it works. Here's a sample of that information:

PID TTY STIME COMMAND 4 ? Apr 22 *** unknown *** 1412 ? 09:03:14 \SystemRoot\System32\smss.exe 1528 ? 09:03:17 \??\C:\WINDOWS\system32\csrss.exe 1552 ? 09:03:22 \??\C:\WINDOWS\system32\winlogon.exe 1600 ? 09:03:24 C:\WINDOWS\system32\services.exe 1612 ? 09:03:24 C:\WINDOWS\system32\lsass.exe 1812 ? 09:03:25 C:\WINDOWS\system32\nvsvc32.exe 1152 ? 09:03:28 C:\Program Files\Symantec\Symantec Endpoint Protection\Smc.exe 1908 ? 09:03:32 C:\Program Files\Common Files\Symantec Shared\ccSvcHst.exe 752 ? 09:03:33 C:\WINDOWS\system32\spoolsv.exe 1860 ? 09:03:42 C:\WINDOWS\system32\svchost.exe 1320 ? 09:03:43 C:\Program Files\Google\Google Desktop Search\GoogleDesktop.exe

I needed to merge the two sources of information together. I started in the shell by chaining a few tools together, but it became awkward and inefficient. I switched to Perl, and hacked together a script that produces output like this:

Connections: 25 3772: 0.0.0.0:80 0.0.0.0:0 C:\Program Files\Apache Software Foundation\Apache2.2\bin\httpd.exe 1988: 0.0.0.0:135 0.0.0.0:0 C:\WINDOWS\system32\svchost.exe 4: 0.0.0.0:445 0.0.0.0:0 Windows System Process 3748: 10.0.1.169:1402 74.125.19.147:80 C:\Program Files\Google\Google Desktop Search\GoogleDesktop.exe 3464: 10.0.1.169:1520 204.2.160.49:80 c:\Program Files\Microsoft IntelliType Pro\dpupdchk.exe 3316: 10.0.1.169:1538 10.0.1.2:1025 C:\Program Files\Microsoft Office\OFFICE11\OUTLOOK.EXE 652: 10.0.1.169:1828 205.188.1.113:5190 C:\Program Files\Pidgin\pidgin.exe

Don't overlook how beautifully the IP and port are aligned. :) The source is available in my Subversion repository as listening.pl.

Installing FusionReactor 3 in ColdFusion 8 on CentOS 5

I document changes to web application cluster nodes to make the procedure repeatable, and for future reference. Recently I installed FusionReactor on CentOS 5 servers using the manual installation instructions. I couldn't use the installer program because these boxes don't run X11, and I prefer to do the installation from the command line anyway. I used the instructions from FusionReactor Installation Guide on the first attempt to install the software. After troubleshooting a few problems, I made explicit instructions for the installation.

Locate the current release of FusionReactor 3 for Linux in an RPM package; see FusionReactor Manual Installation section on the downloads page. Grab the URL for the download, and perform the following:

# Download the RPM and verify wget http://www.fusion-reactor.com/fr/FusionReactor-Download-Link md5sum FusionReactor.rpm rpm -Uvh FusionReactor.rpm # Stop Apache and ColdFusion service httpd stop service coldfusion_8 stop # Modify FusionReactor permissions chown nobody $FR_HOME chown -R nobody $FR_HOME/html chown -R nobody $FR_HOME/etc chown -R nobody $FR_HOME/instance # Configuration for defaults CF8_HOME=/opt/coldfusion8 FR_NATIVE_LIBS=$CF8_HOME/lib FR_JAVA_LIBS=$CF8_HOME/runtime/servers/coldfusion/SERVER-INF/lib FR_HOME=/opt/fusionreactor FR_PREFS=com/intergral JAVA_SYSTEM_PREFS=/etc/.java/.systemPrefs # Copy Java and native files if [ ! -d $FR_JAVA_LIBS ]; then mkdir $FR_JAVA_LIBS fi cp $FR_HOME/etc/lib/fusionreactor.jar $FR_JAVA_LIBS cp $FR_HOME/etc/lib/libFusionReactor.so $FR_NATIVE_LIBS # System Java prefs if [ ! -d $JAVA_SYSTEM_PREFS/$FR_PREFS ]; then mkdir -pm 777 $JAVA_SYSTEM_PREFS/$FR_PREFS fi chmod 777 $JAVA_SYSTEM_PREFS

The next part of the installation requires copying a chunk of XML from the FusionReactor source into the ColdFusion server configuration:

# Copy the <filter/> and <filter-mapping/> vim $FR_HOME/etc/conf/fusionreactor-web.xml $CF8_HOME/runtime/servers/coldfusion/SERVER-INF/default-web.xml

The firewall must be updated to allow HTTP access to the FusionReactor interface. That making the change, Apache and ColdFusion can be brought up.

# Update firewall # -A RH-Firewall-1-INPUT -m tcp -p tcp --dport 8088 -j ACCEPT vim /etc/sysconfig/iptables service iptables restart # Start Apache and ColdFusion service coldfusion_8 start service httpd start

Immediately login to the FusionReactor and change the password for the Administrator account; disable the Manager and Observer accounts. Viola! Please let me know if this is useful to you.

ColdFusion Stale Class Files

While performing a deploy of my Job Scheduler application last night, I encountered a weird problem with ColdFusion not picking up new versions of CFC files. The environment is a network of CentOS 5 servers. The load balancer directs HTTP requests to a suitable web server. Both web servers run Apache HTTP 2.2 and ColdFusion 8.01; they automount (NFS) each user's home directory within which are web root directories containing CFML files. When updating files in a user's home directory, I login as the user from the administration system and make changes to the appropriate web root -- again, over NFS. Typically, this all works perfectly.

The issue last night was that a new version of Transfer was not being compiled by the ColdFusion services. I could see that /opt/coldfusion8/wwwroot/WEB-INF/cfclasses/cfConfiguration2ecfcXXX.class was not being replaced when a new version of /home/user/wwwroot/transfer/com/config/Configuration.cfc was in place. The old version was Transfer 0.6.3; the new version is Transfer 1.1. I had moved the old version to /transfer-0.6.3 and unzipped the new version as /transfer. There is another application in the user's web root that uses Transfer. Perhaps it had a copy of the CFC in its application scope, and that caused ColdFusion to disregard the updated file. Restarting ColdFusion didn't solve the problem. I shut down the web server “B” so all requests made through the load balancer would arrive at web server “A”. I made a few test CFML pages to verify that some files would be compiled by ColdFusion -- that worked fine.

Unable to update Transfer to the new version, I created a mapping in the Application.cfc for the Job Scheduler:

this.webRoot = getDirectoryFromPath(expandPath("/")); this.appPath = getDirectoryFromPath(getMetaData(this).path); this.appRoot = replace(this.appPath, this.webRoot, ""); this.mappings = structNew(); this.mappings["/"] = this.webRoot; this.mappings["/transfer"] = this.webRoot & "/transfer_1_1";

That workaround enabled the deployment to proceed, but I'm still not completely satisfied.

Update:
I should have mentioned that the “Trusted cache” and “Save class files” options were disabled and it didn't affect the problem. I also deleted cfConfiguration2ecfc*.class manually to force ColdFusion to recreated them. It did -- but the wrong version again.