Compiling Custom Event Gateways For Dummies
First off, let me say that I am not a java programmer. I've done a lot of java integration in coldfusion, but that has little to do with actual java programming.
I recently had a need for a very simple event gateway - one that would basically make a CFC method call every XX seconds. Kind of like a scheduled task, except scheduled tasks unnecessarily tax the web server and run no more often than once every minute.
There were many "GOTCHYAS" along the way in this experience and I want to share some of them. If you, like me, are not a real java programmer, you may find some of these tips useful.
I chose to start with the DirectoryWatcher gateway - an actual working gateway that read a config file where things occurred on an interval. In the section where it read the properties file, I removed all the properities I didn't want, leaving only two... "interval" and "callFunction" (which was originally named "changeFunction"). Then I removed all the unnecessary code that involved checking for the existence of directories and getting directory listings and such. Then I tried to compile:
Problem #1 - no java compiler
Coldfusion includes the Java Runtime Environment (JRE), but not the SDK, which is what you need to compile things. The solution here was simple - download the JDK from http://java.sun.com. Make sure you get the same JDK version that coldfusion is running - in my case, 1.4.2 (technically, 1.4.2_05_b04, but Sun only made 1.4.2_10 available, the latest release, and that seemed to work).
So I got it installed and tried to compile. And I got 24 errors. I didn't even realize there were that many lines in the code! Most of them said "Can't resolve symbol" or "Unable to resolve symbol" or something. I did a little googling and found out that I needed a class path.
Problem #2 - defining your class path
Well, the java compiler is kinda stupid, and doesn't know where all the tools on your system are located, so you have to tell it by setting a classpath environment variable, or putting the classpath into the command line. To figure out what jar files had to be included, I looked at $CFHOME/gateway/src/build.xml and saw 4 jars that had to be included, so I set my path like this:
PLATFORM NOTE: I'm using Linux, and my shell is bash. I'm not here to tell you how to set environment variables in UNIX shells or windows. If you need help properly setting environment variables, you might find this classpath tutorial helpful.
export CLASSPATH=".:/root/j2sdk/lib/tools.jar:$CFHOME/lib/cfusion.jar:$CFHOME/lib/log4j.jar:$CFHOME/runtime/lib/jrun.jar:$CFHOME/gateway/lib/examples.jar"
A couple important things to note:
- each entry in the classpath is separated by a colon, and there should be no colon at the beginning or the end of the classpath
- the first entry should always be a period, telling java and the java compiler to always look in the current directory.
- The classpath must always include the tools.jar file, or pretty much nothing will work! I forgot this part initially and it took me a bit to figure it out.
Okay, so my classpath is now set and I tried again.
Problem #3 - weird bug involving abstracting and overriding the accept() method
The DirectoryWatcher gateway example is extends the EmptyGateway class - but it also implements the FilenameFilter class. Since i'm not doing any work with filtering filenames, I had to remove the "implements FilenameFilter" from the public class declaration in the source file.
After doing this, I compiled successfully. Yay! The documentation says to put it into a jar file and then place it in the gateway lib directory.
Worked fine and I moved it to the appropriate lib folder, and restarted Coldfusion. Consult the CF documentation for the appropriate folder, it's different if you're using CF standalone or j2ee.
So I then logged into the CF Administrator to add the Gateway Type.
Problem #4 - full java class? What the heck does that mean?
I had no idea what to put here. The documentation didn't help either, so I looked at the DirectoryWatcher class in the CF Admin, and it said the class was "examples.watcher.DirectoryWatcherGateway". I looked at the source code for that class, and saw "package examples.watcher" and figured that this must be where it came from. So I changed it from "examples.watcher" to "package com.opensourcecf.gateways", then moved my files around a bit, so that my source code path was $CFHOME/gateway/src/com/opensourcecf/gateways/SimpleGateway.java
I then recompiled without error again, copied it to the gateway lib folder, and restarted coldfusion again.
I was able to successfully add the Gateway Type using the full java class "com.opensourcecf.gateways.SimpleGateway"
What fun!
I'll be releasing my SimpleGateway class as open source, as people might find it useful, and when I do (maybe tomorrow), I'll blog about it at www.opensourcecf.com and I'll post a direct link to the blog entry here.