« Time For a New Toy | Main | ColdFusion, JRun and Flex TechNotes Available as RSS Feeds »
June 08, 2004
Loading Class File Remotely in ColdFusion
Spike Milligan of Spike-fu made a very cool post recently entitled "Loading java class files from a relative path" which demonstrates a technique for loading class files through a local file URL so that you don't have put them in your classpath. I thought that was very innovative, and decided to take it a step further.
The point of Spike's post was to make server configuration easier. To make configuration easier still, why not store all your class files on one central server, and use a similar technique to load them remotely? I wrote a component called RemoteClassLoader that does it for you:
<cfcomponent displayName="RemoteClassLoader" output="no">
<cfset my = structNew()/>
<cffunction name="setRemoteClassPaths" returnType="void" output="no">
<cfargument name="classPaths" type="array" required="true"/>
<cfset var urls = arrayNew(1)/>
<cfset var arrayFactory =
createObject("java", "java.lang.reflect.Array")/>
<cfset var urlClass =
createObject("java", "java.net.URL").init("http://macromedia.com")/>
<cfset var urlArray = arrayFactory.newInstance(urlClass.class, 0)/>
<cfloop from="1" to="#arrayLen(arguments.classPaths)#" index="i">
<cfset urls[i] =
createObject("java", "java.net.URL").init(arguments.classPaths[i])/>
</cfloop>
<cfset my.loader =
createObject("java",
"java.net.URLClassLoader").init(urls.toArray(urlArray))/>
</cffunction>
<cffunction name="getRemoteClass">
<cfargument name="class" type="string" required="true"/>
<cfreturn my.loader.loadClass(class)/>
</cffunction>
</cfcomponent>
Using the component above, I was able to load Spike's HelloWorld class right from his server, instantiate it, and call functions on it. The code looks like this:
<cfscript>
remoteClassLoader =
createObject("component",
"com.macromedia.net.RemoteClassLoader");
urlArray = arrayNew(1);
urlArray[1] = "http://www.spike.org.uk/downloads/";
remoteClassLoader.setRemoteClassPaths(urlArray);
helloWorld = remoteClassLoader.getRemoteClass("HelloWorld");
</cfscript>
<html>
<cfoutput>#helloWorld.newInstance().sayHello()#</cfoutput>
</html>
A couple of notes:
- The code above assumes that the RemoteClassLoader component is in the package "com.macromedia.net" (which is where I put it after I wrote it before checking it into CVS).
- I haven't tested this with jar files, but it should work fine.
- I wrote this in about 5 minutes, so you might want to bulletproof it before using it in a production environment.
Thanks for the inspiration, Spike!
Posted by cantrell at June 8, 2004 02:49 PM | References
Comments
BTW, you can use Class.forName("java.net.URL") to get an instance of Class for java.net.URL instead of creating a dummy URL instance.
Posted by: Matt Liotta at June 8, 2004 04:11 PM
Can I say this is cool and useful....:)
Posted by: Patrick Whittingham at June 9, 2004 09:19 AM
I'm getting a " you do not permission" error.
Any idea why?
Posted by: Sophek Tounn at June 9, 2004 05:42 PM
Are you working on a local or remote server? Does your server have sandbox security enabled?
Christian
Posted by: Christian Cantrell at June 9, 2004 05:51 PM
Hello,
I tried it on both my local and remote system.
Thanks
Posted by: Sophek Tounn at June 10, 2004 06:08 PM
it would be a great idea but i think this technique pulls a rather large amount of overhead?? i've tried spike's technique with my geoLocator & its performance went into the crapper (40ms vs 240ms).
any ideas?
Posted by: PaulH at June 12, 2004 10:40 AM
It doesn't surprise me that there might be some additional overhead the first time the class get loaded, but the JVM should cache the class, so the creation of additional instances shouldn't be any slower than if the class had been loaded through the classpath.
Posted by: Christian Cantrell at June 13, 2004 11:31 AM
yeah that appears to be the case. thanks.
another thing i'm seeing is that protected classes can't be accessed using this technique. i'm trying to make my non-gregorian calendar CFCs (based on ibm's icu4j lib) easier to distribute & ran into this for a few classes (primarily icu4j's DateFormat). any ideas?
Posted by: PaulH at June 24, 2004 03:54 AM
Hi,
nice, thank you for this information. It helped me a lot :-)
Posted by: Lastminute Reisen at July 7, 2004 02:27 PM
Hi Christian,
i have put in the urlpath not a class but a .jar.. and it work fine:
remoteClassLoader = createObject("component", "RemoteClassLoader");
urlArray = arrayNew(1);
urlArray[1] = "http://localhost/test/jtidy/Tidy.jar";
remoteClassLoader.setRemoteClassPaths(urlArray);
tidy = remoteClassLoader.getRemoteClass("org.w3c.tidy.Tidy");
tidy.newInstance().setQuiet(false);
tidy.newInstance().setIndentContent(true);
tidy.newInstance().setSmartIndent(true);
tidy.newInstance().setIndentAttributes(true);
tidy.newInstance().setWraplen(1024);
tidy.newInstance().setXHTML(true);
Posted by: Giosi at October 6, 2004 10:11 AM