|By Guy Rish||
|August 8, 2001 12:00 AM EDT||
Prior to ColdFusion 4.5 a developer could only write CFX tags in a binary language that supported the dynamic linking capabilities of the target platform.
For Windows it was C/C++ and Delphi and the like, any language that could create a DLL. For the UNIX platforms, it was pretty much the same thing - only with shared objects. Naturally anytime a CFX was distributed it needed to be compiled for the different platforms or the source code was required - which is assuming, of course, that the CFX was even designed to be ported!
Now that CFX tags can be written in Java it is a write once and run anywhere strategy, which is already one of the major pillars of the Java philosophy. This makes things simple: unless native calls are made, the CFX is guaranteed to run on both platforms without change.
Keeping It Simple
The folks at Allaire did us (the ColdFusion developer community) a wonderful service by making the Java CFAPI fairly simple. In fact, creating a basic custom tag is no more difficult than implementing a Java interface.
public interface CustomTag
public void processRequest(Request request, Response response)
The CustomTag interface in the CFAPI has only one method to implement: processRequest. This method receives two arguments, a Request object and a Response object, both from the CFAPI. It is through these two objects that the Java CFX receives information and provides output.
The CFAPI Model
All of the classes and interfaces of the CFAPI are shown in the UML model (see Figure 1).
There are a number of other classes and interfaces in the CFAPI library, but most of them are not designed for direct interaction with the developer. These are the native bindings and wrappers that hook into the Cold-Fusion Server. Of all of the classes in the CFAPI, there are only four you are likely to use directly: CustomTag, Request, Response, and Query.
This interface is the basis for all the custom tags derived from the CFAPI. Every tag must implement this interface in order for the ColdFusion Server to be able to hook it. There is only one method signature that needs to be implemented: processRequest (see Table 1). This method receives instances of two of the other classes: Request and Response.
This interface provides a way for the custom tag to receive information from the system or the calling logic (see Table 2).
This interface provides a way for the custom tag to return information to the calling logic (see Table 3).
This interface provides a way for the developer to manipulate a recordset (see Table 4).
I fear that I must exercise that tired example again; Listing 1 is a simple "Hello, World" Java CFX. As can be seen on Line 14, tag attributes can be retrieved through the Request object by means of the getAttribute method. As seen in Line 19, output can be returned to the ColdFusion Server by using the write method of the Response object.
Registering a Java CFX
As with their binary cousins, Java CFXs need to be registered in the ColdFusion Administrator. The process is fairly simple and - like almost all things in ColdFusion - does not require drilling through many screens.
The CFX Tags panel can be accessed from the ColdFusion Administrator. Starting from the left-hand navigation, under the Extensions menu is the hyperlink "CFX Tags". All the registered CFXs (binary and Java) are shown on the main CFX registration screen shown in Figure 2.
Enter a name for the CFX, set the type to be Java, and press the "Add" button. This will direct you to the second screen in the registration process, shown in Figure 3.
This screen is comprised of three entry fields: Tag Name, Class Name, and Description. The Tag Name field is the name by which the CFX will be referenced from within the template. In the case of the "Hello, World" example, created in Listing 1, I entered "Hello". So whenever the interpreter encounters a "cfx_hello" it will know to load the class file for this tag.
The Class Name entry specifies the class implementing the CFX's functionality. This class must exist somewhere in the CLASSPATH setting of the ColdFusion Server (configurable from the Java Setting panel, see Part 1 of this series in CFDJ, Vol. 3, issue 1).
When necessary, be certain to use the full class name with package path. Typically I put my CFXs (Java or otherwise) in the CFX subdirectory of the ColdFusion Server installation directory. This runs a little contrary to certain recommendations made in the ColdFusion documentation, which I will discuss later. The Description field is optional and can be used to describe the functionality of the library registered.
Testing the CFX
It is important to test the newly registered CFX since the Cold-Fusion Server does not verify any of the registration information until the CFX is first called. In the case of our "Hello, World" CFX this is rather simple. In Listing 2 I have created a simple template that called the "cfx_hello" tag in the body of an otherwise empty HTML document.
Now that you have a grasp of the basics, let's step it up a bit. As a rule, CFXs cannot pass or return complex data types (the sole exception to this is the CFML query type). More specifically, the ColdFusion Server will allow for one CFML query to be passed into the CFX and one to be passed back. You can pass a CFML query in by specifying the name of the query in an attribute to the CFX named Query.
A reimplementation of the "Hello, World" CFX, shown in Listing 3, demonstrates how to work with an incoming CFML query. The template, shown in Listing 4, will query a database to retrieve a list of names, which it will pass to the CFX through the Query attribute.
The CFX is not that much of a departure from the "Hello, World" code in Listing 1. However, instead of receiving a single name in the attribute Name, the incoming query is looped over and the Name column is concatenated.
During development, code often gets changed rapidly and must be tested just as rapidly - and CFX tags are no exception. However, trying to rerun a Java CFX is not as simple as rerunning a newly compiled application. Once the CFX has been loaded by the JVM, it stays cached and the ColdFusion Server must be restarted to flush it from the JVM. The DebuggingFactory I created for Part 4 of this series (CFDJ, Vol.3, issue 6) is of little use here since the ColdFusion Server is invoking the CFX class and cannot be made to use that class.
There is actually a way to hijack Allaire's CFX class loader, but it's a sticky operation at best. The ColdFusion 4.5 documentation (Developing Web Applications with ColdFusion, Chapter 18: "Building Custom CFAPI Tags") states that if CFXs are deployed in the same configured directory as the cfx.jar file, the ColdFusion Server will check the timestamp on the class file and reload it if there have been changes. This can be further ad-justed by passing an additional attribute to the CFX called Reload. For CFXs stored in the configured directory, the Reload attribute indicates to the ColdFusion Server whether the timestamp should be checked and what the reload rule should be (see Table 5).
This same documentation recommends that all Java CFX tags should be both debugged and deployed from this location. I would recommend against deploying production class files from the location for two reasons:
1. There is an additional performance hit to check the CFX class file each time for modifications.
2. It is a potential security risk to have a deployed production environment module reload without an explicit administrator request.
This situation gets a little better in ColdFusion 5.0, but the points I've made still remain.
For all their power (all CFXs - binary and Java alike), there are inherent limitations in the CFX model. These limitations have existed since the introduction of the CFX architecture and will continue to persist through version 5.0 (the Windows version being just newly available at the time of the writing of this article).
CFX tags can only be singular tags. This means there's no end tag, and thus no body or subordinate tags. This effectively makes CFX tags analogous to simply executing external programs.
Limited Relationship to Calling Logic
Undoubtedly CFX tags enhance the available power of the ColdFusion Server, but their implementation model hobbles them some. There is little connection with the calling logic of the CFX. There is no way for the CFX to find out information about its parent tag, it cannot trace the tag stack or access the Caller scope as other CFML-based tags do.
Complex Data Types
With the sole exception of a single incoming and outgoing query, no complex data types may be passed in or out of the CFX tag. This is a severe limitation that has not been corrected even in version 5.0 (there is a work around that I will discuss later in this series).
Difficulty in Debugging
Since the ColdFusion Server does not have specific hooks in it for stepping specific binary code or Java bytecode into either platform, debugging CFX tags can be difficult. Allaire has provided a number of classes to assist with this, but it isn't a silver bullet to the problem.
Wrapping It Up
Given the simplicity of writing CFXs in Java and the extensive libraries available, it makes sense to write tags in this manner. They are often more robust in functionality and frequently faster in execution than tags written in CFML. Naturally tags written in C/C++ will have better performance, but in many cases the loss of platform independence and thus the need to maintain two different code bases outweighs that gain.
In Part 6, I'll introduce you to some of the more advanced features of the CFX model, the recommended Allaire debugging techniques, and a couple of the benefits of using the JVM.