The CFC Proxy API was introduced as a supported feature in CFMX 7.01. It allows you to call ColdFusion Components (CFCs) from Java classes such as a standalone servlet running in the same JVM. In order for this to work, the Java class must be loaded by the ColdFusion classloader rather than a higher level classloader in the J2EE container. To load a Java class with the ColdFusion classloader, the class's jar file must be specified in ColdFusion's web.xml under the cf.class.path parameter. To avoid managing multiple copies of a custom jar file between ColdFusion instances clustered on JRun, you can put a single copy of the custom jar file under a central location outside the JRun root directory. Then modify the web.xml for each CF instance to point to that jar file in the cf.class.path entry. Surprisingly, there is no documentation on using CFCProxy on livedocs.adobe.com, but instead you can find this reference on Ben Forta's website. The reference describes the API and provides a brief example implementation. A few details are left out such as how to compile the custom Java class, so I'll provide a quick walk through of how I set all this up...

A Sample CFC saved as C:\TEMP\CFCProxy\Test.cfc

view plain print about
1<cfcomponent>
2 <cffunction name="getData" returntype="struct">
3 <cfargument name="msg" required="Yes">
4 <cfscript>
5 st = StructNew();
6 st.name = "michael";
7 st.email = "remin@macromedia.com";
8 st.date = "#now()#";
9 st.message = msg;
10 return st;
11
</cfscript>
12 </cffunction>
13 </cfcomponent>

CFCInvoker Java source file saved as C:\TEMP\CFCProxy\CFCInvoker.java

view plain print about
1import coldfusion.cfc.CFCProxy;
2import coldfusion.bootstrap.BootstrapClassLoader;
3import javax.servlet.http.HttpServletResponse;
4import javax.servlet.http.HttpServletRequest;
5 public class CFCInvoker
6 {
7 public coldfusion.runtime.Struct invoke()
8 {
9 coldfusion.runtime.Struct map = null;
10 try {
11 /*
12     declare variable for storing reference to CFCProxy
13 */

14 CFCProxy myCFC;
15 /*
16     instantiate CFC
17 */

18 myCFC = new CFCProxy("C:\TEMP\CFCProxy\test.cfc");
19 /*
20     Build arguments array
21 */

22 Object<] myArgs = {"Java invocation working"};
23 /*
24     invoke method from CFC. It returns a structure.
25 */

26 map = (coldfusion.runtime.Struct) myCFC.invoke("getData", myArgs);
27 } catch (Throwable ex) {
28 ex.printStackTrace(); }
29 return map;
30     }
31}

Batch File Compiler saved as C:\TEMP\CFCProxy\Compile_and_Jar_CFCInvoker.bat. In order to import all the required classes such as BootstrapClassLoader, HttpServletRequest, and CFCProxy the cfusion.jar, cfmx_bootstrap.jar, and jrun.jar need to be pulled into the classpath. Adjust the paths to match your system (or write a shell script analog) and double click to run.

view plain print about
1@echo off
2echo This will compile and jar up the CFCInvoker Java source file
3echo Press Control+C to abort.
4pause
5SETLOCAL
6set JRUN_HOME=C:\JRun4
7set CF_HOME=%JRUN_HOME%\servers\cfusion\cfusion-ear\cfusion-war
8set JAVA_HOME="C:\Program Files\Java\jdk1.6.0"
9set CLASSPATH=.;%CF_HOME%\WEB-INF\cfusion\lib\cfusion.jar;%CF_HOME%\WEB-INF\lib\cfmx_bootstrap.jar;%JRUN_HOME%\lib\jrun.jar;
10set PATH=%JAVA_HOME;.;%PATH%
11javac -classpath %CLASSPATH% CFCInvoker.java
12jar -cvf CFCInvoker.jar CFCInvoker.class
13echo Done
14ENDLOCAL
15pause

Modify cf.class.path parameter for each ColdFusion instance's web.xml file. Add the path for the centrally located jar file:

view plain print about
1<context-param id="coldfusion_context_88">
2 <param-name>cf.class.path</param-name>
3 <param-value>
4 ./WEB-INF/cfusion/lib/updates,./WEB-INF/cfusion/lib,./WEB-INF/cfusion/gateway/lib,./WEB-INF/flex/jars,./WEB-INF/cfform/jars,C:/TEMP/CFCProxy/CFCInvoker.jar</param-value>
5</context-param>

Restart All ColdFusion Instances

Test Calling The Java Class by putting a CFCInvoker_tester.cfm in the webroot.

view plain print about
1<cfscript>
2 CFCInvokerObj = createObject("java","CFCInvoker");
3
</cfscript>
4<cfdump var="#CFCInvokerObj.invoke()#"/>

In this example, the CFCInvoker_tester.cfm just creates an instance of the Java class and calls invoke() on it, but a real life example might be that the Java class is a Servlet and is available via URL pattern to accept requests directly.

Since the custom CFCProxy Java class is centrally located in a single jar file outside the ColdFusion or JRun roots it can be shared across multiple instances without worrying about revision differences across the cluster members.