Compound Theory

v2.0

Categories

  1. Transfer
  2. ColdFusion
  3. JRuby
  4. Java
  5. ColdSpring
  6. Squabble
  7. JavaLoader
  8. ColdDoc
  9. 2ddu
  10. AsyncHTTP
  11. OO Analysis and Design
  12. Flex
  13. Railo
  14. XML / XSL
  15. Hibernate
  16. ColdFusion Builder
  17. Fall
  18. Ubuntu
  19. XHTML / CSS
  20. Eclipse
  21. Git
  22. Oracle Database
  23. Usability / UI Design
  24. webDU
  25. cf.Objective()
  26. LWJGL
  27. cf.Objective(ANZ)
  28. Captcha
  29. MAX
  30. Melbourne CFUG
  31. Martial Arts
  32. Random Things
  33. Conduit

Recent Posts

Projects

Recent Comments

17 February 2012 10:06 AM 0 Comments

JavaLoader 1.1, and a Move to GitHub

A couple of new items in this release of JavaLoader:

The new function, swithThreadContextClassLoader() is useful as it is often required when dealing with libraries, such as dom4j, that use the ClassLoader to define singletons or search for implementing classes, and don't allow you to overwrite what ClassLoader they use. Check out the wiki for more details on why this is neccessary, and how easy it is to now do, thanks to our new function!

Also, JavaLoader has been move to GitHub, along with the all the documentation. This should make collaboration much easier moving forward!

Otherwise, make sure to sign up to the mailing list, and enjoy loading your Java.

10 September 2010 05:33 PM 3 Comments

JavaLoader 1.0 Released

JavaLoader 1.0 goes final, with only a minor modification to how trusted source is managed when dynamic compilation is used.

Now, when trusted source is set to true, the compiled JAR is retained, so that on server restart the code does not have to be re-compiled, and can simple be loaded from the existing JAR.  Otherwise, this release is the same as Beta 2.

I hope you all enjoy JavaLoader 1.0

Presenting and Teaching at cf.Objective() 2010

I'm a little behind the times on this blog post - but I am presenting and also teaching a course at cf.Objective() this year.

I will be presenting 2 sessions at the conference:

Dependency Injection Redefined - ColdSpring 2.0: Narwhal

ColdSpring 2.0, codenamed 'Narwhal', is a project that has been going on a little 'behind the scenes', except for the occasional tweet from either myself, or Chris Scott.

In this presentation, we'll look at some of the motivations behind the complete rewrite of ColdSpring for the 2.0 version, and some of the new features that will be available that should make dependency injection easier, and way more flexible than ever before.

I've had in my to-do list a reminder to write a long blog post on what is going on with Narwhal, which I should write at some point soon, so you have a good idea what to look out for.  That being said, Narwhal is taking shape nicely, and I think is going to be a very powerful addition to the ColdFusion framework landscape.

Advanced Java & ColdFusion Integration with JavaLoader 1.0

This talk will focus on the new features of JavaLoader 1.0, and how you can use them to integrate Java with your ColdFusion platform in some new and exciting ways.  If you are interested in JavaLoader 1.0, check out this previous blog post, it gives you a good run down on the new features it brings to the table.

We will also be investigating some of more common 'gotchas' with Java and ColdFusion integration, especially around ClassLoader issues, which should be useful for all involved.


Bob Silverberg and I are also going to be a teaching a 2 day training course, just before cf.Objective():

Hands-On ColdFusion ORM Training

This will be as very hands on session, where Bob and I will be going through building an application using ColdFuson 9's Object Relational Mapper from beginning to end.  This will include many best practices, discussions as well as theory about how the underlying Hibernate engine works with ColdFusion.  No ORM/Hibernate experience necessary.

More detail on the course can be found on our website, and also on the preconference page, where you can also check out all the other fantastic training content.

Don't forget that the early bird pricing for both conference tickets, and training finishes on the 29th of January, which is coming up soon!

cf.Objective() is looking to be a great conference. Hope to see you there!
20 January 2010 11:48 AM 1 Comment

JavaLoader 1.0 Beta 2 Released

This release of JavaLoader 1.0 includes the following fixes and enhancements:
If you aren't aware of the new functionality in JavaLoader 1.0, you can have a look at my previous blog post , the documentation and/or the presentation I did at MAX for more information.

Credit and thanks to Fred Roeber for his contributions to the NetworkClassLoader in JavaLoader.

If you are interested in hearing more about ColdFusion and Java integration please come to cf.Objective(), where I will be presenting on Advanced Java & ColdFusion with JavaLoader 1.0.

In the mean time, download JavaLoader, and please report any bugs that you find.

My Interview on Dzone - ColdFusion and Java Integration

The interview I did with Dzone at the Adobe MAX conference is now online!

In the interview we talk about a variety of topics, mainly centred about how and why to integrate ColdFusion and Java together, but also touching on things like Object Relational Mappers, including ColdFusion 9's integration with Hibernate.

Hope you like it, and please give it a nice 'up' on Dzone.

26 October 2009 11:11 AM 0 Comments

JavaLoader 1.0 Beta Released

JavaLoader 1.0 is moving from Alpha to Beta with only a few small bug fixes and enhancements.

If you are not familiar with JavaLoader 1.0's functionality, you can have a look at my previous blog post , the documentation and/or the presentation I did at MAX for more information.

The was a logic bug in the way that dynamic compilation was occuring across multiple source directories that has now been resolved, and should also ensure that compilation is much faster than it was in the Alpha.

The other enhancement was to allow for relative paths in the Spring integration.  To explain, in the Alpha, you would often end up having to input your beans similar to this:

<coldfusion:cfc id="message"
        script-source="file://${root.path}/model/Message.cfc"
        script-interfaces="com.IMessage"
        />


Which can be a bit of a pain, as injecting a dynamic value for ${root.path} is not as easy in Spring as it is in ColdSpring.

Now, by default, 'script-source' attributes are relative to the calling page, so you can do your bean definitions like this:

<coldfusion:cfc id="message"
        script-source="file:///model/Message.cfc"
        script-interfaces="com.IMessage"
        />


and the path will be worked out for /model/Message.cfc relative to your application path.

Oh, and don't forget - if you are into integrating Java and ColdFusion development, make sure you sign up for the Google Group !

JavaLoader 1.0 Beta can be downloaded here .

22 October 2009 02:48 PM 5 Comments

MAX Presentation Recording: ColdFusion for Java Developers

I had the wonderful opportunity to present and attend MAX for the first time ever this year, and I can honestly say, it was a fantastic time all around.

MAX is completely unlike any other conference I've ever attended, both in terms of its sheer size, and also in terms of the wide gamut of Adobe community members that are in attendance.  I managed to meet a variety of people that I would never have talk to in my regular travels both in term of physical locations and also technological disciplines.

I also had the pleasure of presenting the last session on the last day, so I was very happy when I had a fairly reasonable turn out for my ColdFusion for Java Developers presentation.  The presentation took the perspective that the attendees were/are already doing Java development, but want to port those tools and codebases that they are already using to a ColdFusion environment, so they could take advantage of ColdFusion services and language.  From there we look at the variety of techniques that you can use to enable ColdFusion->Java communication, as well as Java->ColdFusion.  This includes a aan overview of a lot of the JavaLoader 1.0 feature set in the process.

If you are one of these people, and/or you are doing development in both ColdFusion and Java, you can watch the recording of my presentation on Adobe TV .  You may want to skip the first 5 minutes, as for some reason the recording has me doing all my set-up before I start speaking.
07 September 2009 09:58 AM 2 Comments

Talking Java and ColdFusion Integration on CFPanel this week!

At a very ANZ friendly time of Wednesday, 10am Melbourne time, I'm going to be joining super-smart guys Brian Kotek and Barney Boisvert on CFPanel to talk about Java Integration with ColdFusion in the CFPanel Connect Room.

This is obviously a topic that is quite near and dear to my heart, but it is also one that I think often doesn't get its 'surface scratched' (so to speak).  In my experience I often see the information presented is more on the 'how to get set up' side, and less on the deeper details on what can actually be done.

I'm really looking forward to getting a chance to share experience with the other CFPanel members, and really get deeper into some interesting Java and ColdFusion integration, in regards to how people are using it, what benefits they are reaping, and also what problems they have encountered.

For more details, and and all the other time zones, check out the CFPanel post.

Hope to see you in the Connect room!
31 August 2009 12:43 PM 2 Comments

JavaLoader 1.0 Alpha is Released!

JavaLoader 1.0 is a project I've been talking about off and on for the past 6 months or so, and I'm very happy to announce that a release version is now complete.

There are several key new features to JavaLoader 1.0,

Dynamic Compilation

Now if you are working with JavaLoader, you don't have to bundle your Java code into a jar to load.  You can simply specify to JavaLoader which directories are your source directories, and JavaLoader will compile and load them on the fly for you!  JavaLoader will also check to see if your source code has changed, and re-compile it as necessary! 

For example, if I wanted to compile and load a HelloWorld.java (that has a simple 'Hello World' method) in my ./src directory, I could do:

javaloader = createObject("component", "javaloader.JavaLoader").init(sourceDirectories=[expandPath('./src')]);

And then create my HelloWord object as per normal:

<cfset helloWorld = javaloader.create("HelloWorld").init()>
<cfoutput>#helloWorld.hello()#</cfoutput>

No more ANT tasks, no more export to .jars, JavaLoader handles the compilation and deployment of your Java code for you.

ColdFusion Component Dynamic Proxy

For those of you who are not aware of what a Dynamic Proxy in Java is, it is essentially an Object that can mimic an object that implements a given set of Interfaces.  The method invocations against that object are intercepted, and you can essentially do whatever you like with them.

In JavaLoader 1.0, I've written a Dynamic Proxy that you are able to wrap around a CFC, and thereby make Java Objects think they are interacting with a native Java object, but are in fact, talking to your CFC.  When a Java Object calls a method on the Dynamic Proxy, it is passed through and invoke directly on the CFC transparent to your Java layer.

For example, the java.lang.Thread Java object can take an instance of the interface java.lang.Runnable in its constructor argument.  Using JavaLoader's Dynamic Proxy, we can pass it what it thinks is an instance of the Runnable Interface, but is in actuality a ColdFusion Component like so:

//give us access to the CFCDynamicProxy
CFCDynamicProxy = javaloaderloader.create("com.compoundtheory.coldfusion.cfc.CFCDynamicProxy");

//create my Runner CFC
myRunner = createObject("component", "MyRunner").init();

//wrap it in a Dynamic Proxy, that implements Runnable
runnerProxy = CFCDynamicProxy.createInstance(myRunner, ["java.lang.Runnable"]);

//pass it to the Thread and call run()
thread = createObject("java", "java.lang.Thread").init(runnerProxy);
thread.run();

...and suddenly we have true seamless communication from Java to ColdFusion components.

This is actually something I wish I had written three years ago.  It would have radically altered how I would have written a lot of software.

Spring Integration

A natural progression from the Dynamic Proxy, was to implement a Custom Schema in Spring, so that you could instantiate and dependency inject your ColdFusion components with your Java Objects inside Spring itself.

Initialising Spring with JavaLoader is covered in the documentation, but to give you a quick taste, once we have Spring running, we can include a CFC in our spring.xml with:

<coldfusion:cfc id="message"
        script-source="file://home/www/model/Message.cfc"
        script-interfaces="com.IMessage"
        />


Where script-source is the absolute path to the CFC you want to instantiate, and script-interfaces are the Java interfaces that your dynamic proxy will implement, and your CFC has mirrored inside it.

This Component then gets treated like a normal Spring bean, so it can be autowired, injected, aop'd and all the usual functionality that a Spring bean has access to.

There are some downsides to implementing Components inside Spring, so be sure to check out the documentation for more details.

Read More

For more details, have a read of the extended documentation, and have a look at the examples provided in the download.

Since this has become a far larger project than its original inception, I've done away with the Riaforge Forum, and have started a new javaloader-dev google group for support and discussion of JavaLoader and Java and ColdFusion integration.

While I'm very confident in the code that I have written for JavaLoader 1.0, I decided to call it an Alpha, simply because it has only really been tested by me and my Unit Tests.  Knowing from experience that users of Open Source Software have a tendency to use and abuse libraries far above and beyond what the author had ever originally dreamed led me to decide to call it Alpha until the community has really had a good change to play with it.

Please download JavaLoader 1.0, take it for a spin, sign up for the mailing list, and if you find any problems please do let me know.
31 July 2009 08:10 AM 0 Comments

Speaking at MAX this year - ColdFusion for Java Devlopers

This year it is going to be my absolute pleasure to be attending and presenting for the first time ever at the Adobe MAX conference.

My presentation is entitled ColdFusion For Java Developers and is scheduled for Wednesday, 5:00pm.

Primarily aimed at Java developers, it is going to cover a myriad of ways that you can integrate your already existing Java code base into a ColdFusion application, and also get your Java model talking seamlessly to your ColdFusion code base.

The official synopsis is:
Ever since ColdFusion was re-implemented as a J2EE application, the benefits of combining Java and ColdFusion application development have been easy to see, and widely used across the ColdFusion landscape.

This talk will look at some of the ways we can already take advantage of common Java libraries in ColdFusion, and enable Java developers to leverage the libraries and frameworks that they are already using. We will also be looking at how Java developers can seamlessly leverage the dynamic scripting language of ColdFusion, within their Java code, to easily enable them to take advantage of some of the RAD features that come bundled with ColdFusion.

That being said, if you are a ColdFusion developer who likes to also work with Java, you may wish to come along, as there will be several techniques demonstrated that will be provided by the forthcoming JavaLoader 1.0 release that should (hopefully) interest you greatly.

I look forward to seeing you all at MAX, and also at the ColdFusion Unconference!
15 May 2008 04:59 AM 5 Comments

JavaLoader 0.6 Released

Not a huge amount to report. This release simply re-orders some of the class loading, so it is child first.

This is important in case you load up a newer (or older) version of a library that ColdFusion already has access to, and you want to make sure you get the library you want, not the library loaded by ColdFusion.

That and I fixed a bug in the JavaProxy.cfc that was sent to me a loooong time ago, that will fix an issue with resolving overloaded Java Methods.

JavaLoader can be downloaded from here.
02 October 2007 01:01 PM 7 Comments

Javaloader v0.5 Released

Here is the release of JavaLoader, version 0.5.

It pretty much does exactly the same thing that the previous versions did, however, it now works in ColdFusion 8, when the setting 'Disable access to internal ColdFusion Java components' is turned on, as it uses its own JavaProxy CFC, which may often be turned on on shared hosts.

That's really about it, nothing more interesting than that.

Download JavaLoader v0.5 from here.

Writing my own JavaProxy for ColdFusion 8 using onMissingMethod

First of all, you may be wondering 'what on earth is a JavaProxy?', well, to answer that question, it is the Java class that does all the work behind the scenes in ColdFusion to allow you to be able to write all that Java code in-line in your ColdFusion CFCs and CFM pages by taking the Coldfusion invocations you have implemented, and passed them to the native Java objects that you want to use.

To further your understanding, if you are at all interested, you can also read up on the proxy design pattern here.

Now, what some people may or may not realise, is that inside JavaLoader, I create an instance of the coldfusion.runtime.java.JavaProxy class, so it becomes really easy for developers to create and use instances of Java objects that are loaded from external .jar files within their applications.  I have a good blog post on doing this here.

Now just the other day, I became aware of a new setting in ColdFusion 8 entitled 'Disable Access to internal ColdFusion Java components', that really threw me for a bend.

For people who run shared hosts, they probably think of this as a g-d send, in that it will disable access to coldfusion.runtime.ServiceFactory - and for that, I totally understand, however, it completely locks down access to any Java object that sits under the coldfusion.* package space.

What does this mean? It means that JavaLoader, no longer works, along with any other project that also uses JavaLoader could quite potentially not work on some shared hosts providers that have upgraded to ColdFusion 8!

Why did Adobe decided to do this? Not so sure! However, with the power that we have in ColdFusion 8, we are able to implement our own JavaProxy, that should be able to be seamlessly interchanged with the ColdFusion native JavaProxy!

(Disclaimer: This is the first run at this code, and it works in the given tests I have tried on it.  I will be running it against all the unit tests on Transfer, and when they all work perfectly, and Transfer can run with this CF8 restriction in place, I will release the full code as part of a new version of JavaLoader)

There are two things that allow us to do this -
  1. Nothing stopping us from using Java Reflection to dynamically call methods on a Java Class or Instance.
  2. In CF8 we got 'onMissingMethod()' - so we have a hook into every method that is fired on a CFC, regardless of whether or not it has been implemented.
For those of you who aren't that familiar with the term reflection - it essentially means that we are able to introspect a Java Class or Object, determine what methods and/or properties it has, and dynamically call them at run-time.  If you want to read more, the Java site has a whole tutorial on reflection.

So, first of all, let's look at the few different ways you can instantiate and use ColdFusion Java Objects, we'll use an ArrayList as an example, so that we know what we need to support in our own JavaProxy. 
I will use 'createObject' here, but it could also just as easily be JavaLoader.create(className) to create an instance of the JavaProxy.
  1. array = createObject("java", "java.util.ArrayList").init();
    array.add(obj);

    - This would be the most common, and generally the 'best' way of instantiating a Java Object in CF, as it calls the constructor straight away, with the appropriate arguments, and is the closest you will get, in style, to implementing a real constructor.
  2. array = createObject("java", "java.util.ArrayList");
    array.init();
    array.add(obj);

    - I've seen this sort of code before... to me, it seems a bit weird to split out the constructor, but it works, and you always know that the object has been instantiated.
  3. array = createObject("java", "java.util.ArrayList");
    array.add(obj);

    - This is what I feel is the 'worst' way of using Java objects in CF as the no argument default constructor is called implicitly, which means you really have no control, and it can lead to all sorts of weirdness in your application if you don't track what has been actually instantiated and what hasn't.
  4. Collections = createObject("java", "java.util.Collections");
    sortedArray = Collections.sort(array);

    - This case shows where static methods are called, in which case, there is no constructor.
  5. Color = createObject("java", "java.awt.Color");
    black = Color.black;

    - This is where we want to be able to retrieve a static property.
Okay, so we have our work cut out for us! But all this is very much possible!

So, the first decision to make, is that all of our internal methods on the JavaProxy.cfc are going to start with an underscore.  This is so that any method that we write, doesn't interfere with the onMissingMethod's we want to be able to pick up.  Also as we need to implement a special 'init' method, that isn't the constructor for the JavaProxy, but instead is a constructor for the Java object the JavaProxy represents, so we will have a _init(class) method that instantiates the JavaProxy.

I'm not going to show all the code here, just the relevant parts, but don't worry, you will be able to see it in the next version of JavaLoader.

So the _init method will do the following things -
  1. Take a Java Class as an argument, and store it in state
  2. Store some helpful Java Objects in some setters.
  3. Set the Static Fields of the Class the JavaProxy represents to the this scope
  4. Store all the Method objects of the Class in a struct of arrays for easy lookup (more on this later).
First of all, we'll set the Static Fields to the this scope.  It is actually very straight forward -

<cffunction name="_setStaticFields" hint="loops around all the fields andsets the static one to this scope" access="private" returntype="void"output="false">
    <cfscript>
        var fields = _getClass().getFields();
        var counter = 1;
        var len = ArrayLen(fields);
        var field = 0;

        for(; counter <= len; counter++)
        {
            field =fields[counter];
            if(_getModifier().isStatic(field.getModifiers()))
            {
               this[field.getName()] = field.get(JavaCast("null", 0));
            }
        }
    </cfscript>
</cffunction>

For reference
So what are we doing here? Well, we ask the Class for all of it's Fields, then we look around them, and then interrogate into whether or not they are static.

Once we know they are static, we retrieve their value, using field.get(), and set them to the same place in the this scope as they would have been in the Java Object.

We are able to use 'null' on the field.get() because the values are static, and are not tied to any actual instance of the Class.

So, what would be nice now, is to be actually be able to instantiate an object!  So let's look at implementing our own 'init' method, so that we can instantiate the Java Class that the JavaProxy represents.

<cffunction name="init" hint="create an instance of this object"access="public" returntype="any" output="false">
    <cfscript>
        var constructor = 0;
        var instance = 0;

        //make sure we only ever have one instance
        if(_hasClassInstance())
        {
            return _getClassInstance();
        }

        constructor =_resolveMethodByParams("Constructor", _getClass().getConstructors(), arguments);

        instance =constructor.newInstance(_buildArgumentArray(arguments));

        _setClassInstance(instance);

        return _getClassInstance();
    </cfscript>
</cffunction>

For reference
So first off, we check to see if we already have created an instance - because we only want one, otherwise weird stuff could happen.  If we do, just give back the Java instance we already have.

The next line, is a little bit more complicated, so we'll break it down.

The _getClass().getConstructors() returns an array of all the possible Constructors that are available for this given class.

The _resolveMethodByParams() method takes a array of Method/Constructor objects, the arguments that have been passed through to the given method, in this case 'init', and find the best match that it can, and returns it.  We'll go into the details of that in a minute.

Once we have the right Constructor object, to get an instance of the Object that our JavaProxy represents, we call 'newInstance' on it, and pass in an array of the objects that make up the arguments that the Constructor needs.

And Preso! We have an instance of our Class! We set it to the state of the Class Instance, and return the newly created instance back out.

Wait! What? Return the new created instance? Why aren't we returning this, that doesn't make sense?  Well actually, if you think about it, it does.

We really would prefer it if ColdFusion did all the heavy lifting when it comes to the bridge between Java and ColdFusion, not only is it more performant, but it also provides a greater deal of consistency across the code base.

So we have code that is:
obj = JavaProxy.init();
obj is actually an instance of the ColdFusion JavaProxy, and then there is a much more seamless line between the new CFC JavaProxy, and the use of the ColdFusion one, which is a very good thing.

That being said, we need to provide support for all the different types of ways that Java Objects can be used and created, so we have to also cater for the other aspects as well.

So without further ado, let's actually fire off some methods!  This is where onMissingMethod really comes into it's power!

<cffunction name="onMissingMethod" access="public" returntype="any"output="false" hint="wires the coldfusion invocation to the JavaObject">
    <cfargument name="missingMethodName" type="string" required="true" />
    <cfargument name="missingMethodArguments" type="struct" required="true" />
    <cfscript>
        var method = _findMethod(arguments.missingMethodName, arguments.missingMethodArguments);

        if(_getModifier().isStatic(method.getModifiers()))
        {
            return method.invoke(JavaCast("null", 0), _buildArgumentArray(arguments.missingMethodArguments));
        }
        else
        {
            if(NOT _hasClassInstance())
            {
                //run the default constructor, just like in normal CF, if there is no instance
                init();
            }

            return method.invoke(_getClassInstance(), _buildArgumentArray(arguments.missingMethodArguments));
        }
    </cfscript>
</cffunction>

Okay, so this is the code that actually takes the methods that are called on the JavaProxy, and passes them to the Java instance or Class as appropriate.

The _findMethod() method, returns the Method that best matches the name of the method that was called, and the arguments that it has.  I will go into detail on that in just a second.

Once we have the correct Method, if it is static, we can then invoke it against 'null', and return it's value.

If it isn't static, then we check to see if we have a instance of the Java Class yet, if not, we create one using the default Constructor, which is the same way that ColdFusion does it.

From here, we are able to invoke the method against the class instance, and return any results that we may get.

Now we can look at the logic that allows us to work out which method matches what in ColdFusion.

Our first step, is to look at the _findMethod method, which is actually pretty simple:

<cffunction name="_findMethod" hint="finds the method thatclosest matches the signature" access="public" returntype="any"output="false">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">
    <cfargument name="methodArgs" hint="the arguments to look for" type="struct" required="Yes">
    <cfscript>
        var decision = 0;

        if(StructKeyExists(_getMethodCollection(), arguments.methodName))
        {
            decision = StructFind(_getMethodCollection(), arguments.methodName);

            //if there is only one option, try it, it's only going to throw a runtime exception if it doesn't work.
            if(ArrayLen(decision) == 1)
            {
                return decision[1];
            }
            else
            {
                return _resolveMethodByParams(arguments.methodName, decision, arguments.methodArgs);
            }
        }

       throw("JavaProxy.MethodNotFoundException", "Could not find thedesignated method", "Could not find the method '#arguments.methodName#'in the class #_getClass().getName()#");
    </cfscript>
</cffunction>

The first thing to know is, that _getMethodCollection() returns a struct of arrays that was set up in our _init(), the key of which is the name of the methods found in the class.  The arrays contained in the struct have all the Methods that have that name, as there may be more than one.

So, the first thing we do, is check to see if the name of the method we need is in the collection of methods we have, if it is we go and grab the array of methods this invocation could possibly be.

You will notice that I have written code that states 'if you only have one option for the method, just return that'.  You may be wondering why, as the parameters of that method may not match what has been passed in.  Well, if that is the case, we will get a runtime error, which is the same as what we would get otherwise, so there is not a huge difference here to just say 'let's give this a shot, if it doesn't work, no big deal', and we save the performance hit of comparing parameters.

If there are more than one option available, then we have to start comparing parameters, and this is where the _resolveMethodByParams() method that we saw earlier does it's hard work.

<cffunction name="_resolveMethodByParams"hint="resolves the method to use by the parameters provided"access="private" returntype="any" output="false">
    <cfargument name="methodName" hint="the name of the method" type="string" required="Yes">
    <cfargument name="decision" hint="the array of methods to decide from" type="array" required="Yes">
    <cfargument name="methodArgs" hint="the arguments to look for" type="struct" required="Yes">
    <cfscript>
        var decisionLen = ArrayLen(arguments.decision);
        var method = 0;
        var counter = 1;
        var argLen = ArrayLen(arguments.methodArgs);
        var paremeters = 0;
        var paramLen = 0;
        var pCounter = 0;
        var param = 0;
        var class = 0;
        var found = true;

        for(; counter <= decisionLen; counter++)
        {
            method = arguments.decision[counter];
            parameters = method.getParameterTypes();
            paramLen = ArrayLen(parameters);

            found = true;

            if(argLen eq paramLen)
            {
                for(pCounter = 1; pCounter <= paramLen AND found; pCounter++)
                {
                    param = parameters[pCounter];
                    class = _getClassMethod().invoke(arguments.methodArgs[pCounter], JavaCast("null", 0));

                    if(param.isAssignableFrom(class))
                    {
                        found = true;
                    }
                    else if(param.isPrimitive()) //if it's a primitive, it can be mapped to object primtive classes
                    {
                        if(param.getName() eq "boolean" AND class.getName() eq "java.lang.Boolean")
                        {
                            found = true;
                        }
                        else if(param.getName() eq "int" AND class.getName() eq "java.lang.Integer")
                        {
                            found = true;
                        }
                        ...
                        else
                        {
                            throw("Ack", "Cannot match this primitive type", "'#param.getName()#' is just not matching");
                        }
                    }
                    else
                    {
                        found = false;
                    }
                }

                if(found)
                {
                    return method;
                }
            }
        }

       throw("JavaProxy.MethodNotFoundException", "Could not find thedesignated method", "Could not find the method '#arguments.methodName#'in the class #_getClass().getName()#");
    </cfscript>
</cffunction>

Woah! That's a lot of crazy code... well, it's not too bad once you break it down.

What we are doing is looping around all the possible methods we have available in the decision array, and trying to see if they match the parameters that we have in our argument struct.

First test says, 'if the number of parameters is different, well, we can't invoke this method', and simply passes it by.

From there, we need to loop around each of the parameters, and see if it can work with the class that the corresponding argument that matches it's place.

You're probably looking at the line that reads '_getClassMethod().invoke(arguments.methodArgs[pCounter], JavaCast("null", 0));' and thinking... what on earth does that do?  Well, it allows us to get to the Class object of that argument.

This is very similar to doing a obj.getClass(), however, I can't do that in all instances.  If an argument is a CFC, then it will try and resolve the method 'getClasss' against the CFC, and most likely throw me an error.  So I have to use reflection!

the _getClassMethod() (this was setup in our _init()) is the actually Method class that represents the 'getClass()' method aforementioned, what I then do is invoke it on the required argument, and this gives me back the Class Object I need for comparison.

Now, a Class object has a great method called 'isAssignableFrom', basically, this says 'If the object is a the same as this Class, or a subclass, or implements this interface, return true'.  This means that if the argument in the method that have been invoked on the CF side isAssignable to the parameter that is required for this method, then this method can be invoked successfully.

The other thing we need to do is map primitive parameters, such as int, char, boolean, etc back to their Object representations.  The nice thing is that Java will map this back and forth at runtime for us, so as long as the values match up, we're good to go.

Once the parameters have all been resolved, we can return the method we have found that works, otherwise, we throw an exception.

That pretty much covers the JavaProxy.CFC.  As I said before, you will be able to see the code in action once I release the new version of JavaLoader, but feel free to ask any questions you may have, I will be happy to answer them.

OMG! I've sold out!

Yes, it's true, I've finally succumbed, and put ads on my site, and switched out the wishlist for a PayPal donate button.  I have finally turned to the dark side.

Do not fear! There are reasons for this!

First of all, the Amazon wish list, didn't really work out.  I'm sure people thought 'I'll buy Mark something from the wishlist, he'll like that', and then quickly realised it can be up to $30 to send stuff to Australia, and that whole idea quickly went out the window.

Second of all, I really want to get out to more conferences overseas.  Unfortunately, while living in Australia is wonderful, we are about as far away from anyone as can possibly be.  This means that travelling can be really expensive.  So this is to say that any revenue and/or donations that I receive from the ads, or from PayPal, will go directly to funding conference travel costs, and also to general open source development costs.

So if you do like the work that I've provided for you guys, please feel free to click the PayPal donate button, its always appreciated, and allows me to come out to more conferences, and put more resources at your disposal.
09 April 2007 10:50 AM 3 Comments

JavaLoader v0.4 Released

One thing that I always gets complaints about with JavaLoader is that you can't delete or rename a .jar file once it is use by ColdFusion, you either have to restart CF, or name the .jar file something funky like 'myOwnJar-10042007.jar', so it has a unique name.  Now with this version of JavaLoader, that issue is no more!

While the .jar file that JavaLoader uses itself does get locked down (I know.. I can't do anything about that one), but .jar files that you use with JavaLoader no longer are locked by the system!

To note, the JavaLoader cfc has had one of its arguments removed - 'loadedClassPathBias', simply because it was more difficult to implement with the new code base, and there didn't seem to be a case for it.  By default,JavaLoader will load the specified jar files before it loads the parent's, if it has one.  Honestly, I don't think this is going to affect a single person, because I would be shocked if anyone actually ever used the option.

Please note there are some issues with memory and JavaLoader, so make sure you put your JavaLoaders in the Server scope.  See here for more details.

If you find any issues, please post to the forums, or contact me directly.

Enjoy!

Using a Java URLClassLoader in CFMX Can Cause a Memory Leak

This is a bug in ColdFusion that can cause memory leaks when using a java.net.URLClassLoader to load external jar files.  Thus, this can cause memory leaks in JavaLoader, Transfer and any other system that uses this technology.  However there is a workaround for the issue.

To explain the problem, first we need to look at some key issues with a URLClassLoader.  URLClassLoaders are notorious for causing memory leaks, because, for them to be garbage collected, all instances to themselves and the classes that they have created need to be garbage collectible.

This means that if you access a class from a URLClassLoader and hold it somewhere in memory, then the URLClassLoader can never be garbage collected.

This is exactly what happens with ColdFusion.

When ColdFusion does some introspection and resolution of ColdFusion code against a Java object, somewhere, deep inside its hidden internals, it keeps a strong reference to the Class object that refers to that Java object.  This means that when the JVM comes along to garbage collect the instance of the URLClassLoader, it can't do it, because ColdFusion has a reference to a class that it loaded somewhere inside.

So, the memory leak only ever actually happens when an instance of a URLClassLoader is no longer available to ColdFusion, as it is never then garbage collected by the JVM.

How does this translate to using JavaLoader? Well, a perfect example of this is where you put an instance of JavaLoader in the application scope, because generally it is used as a singleton.  JavaLoader (and anything that subsequently uses JavaLoader) has an instance of a URLClassLoader inside it.  However, when the application scope times out, the JavaLoader CFC may well be garbage collected, but the URLClassLoader isn't, which can cause a memory leak.

To note however, in production systems the leak is minimised in situations like this, as it is often very rare that the application scope will ever time out.

So what is the workaround for this issue? To note, I have been pushing at Adobe to get a hotfix out for CFMX to resolve this issue, but we can definitely still use this technique now, without having to worry about memory leaks. 

Essentially, the memory leak only happens when the URLClassLoader is no longer available to CF, i.e. an application scope times out, or something similar - so we just need to make sure that it never, ever, times out.  How can we do that? why, put it in the Server scope of course!

Since variables in the Server scope never time out, we don't need to worry about the URLClassLoader (or JavaLoader) being lost and then recreated, as it always exists.  As long as you put it in the Server scope under a key no one will ever need to utilise (I like a hard coded UUID myself)!  Hence we beat the memory leak monster!

I have just committed a fix for Transfer that automatically puts the JavaLoader it uses into the Server scope, so even if your TransferFactory times out, the JavaLoader never will, which means there is no leak, and the RC2 for 0.6.3 will have this as well.

Hopefully Adobe will put out a hotfix for this issue, but until then, put your JavaLoaders in the Server scope.
10 February 2007 06:34 PM 3 Comments

Issue with cfcatch and JavaLoader

This is an issue I came across yesterday while doing some work on Transfer that affects JavaLoader , and generally anything that uses an URLClassLoader to load any external class/jar files.

The issue lies with catching Java exception with <cfcatch>.  The documentation states, that to catch a thrown Java exception you can specify the type in the 'type' attribute of the <cfcatch> tag.  So if we wanted to catch a java.io.IOException, we would do so this way:

<cftry>
   <!--- do some stuff that may throw an exception --->
    <cfcatch type="java.io.IOException">
        <!--- do something with it --->
    </cfcatch>
</cftry>

Now the issue comes when you are using JavaLoader (or anything that utilises any sort of URLClassLoader) and the loaded Java code throws an exception that hasn't been loaded with ColdFusion at start up -

<cfcatch> can't catch the Java Exception by it's specific type!
 
To show you what I mean, I created a simple test bed.

I create a new Java Exception object, 'com.compoundtheory.test.myException', and a class called 'MyThrower' who's sole job was to throw this exception.

Just to note 'jl' is the JavaLoader instance that has loaded my classes.

My test bed looked like this:

<cftry>
    <cfscript>
        myThrower = jl.create("com.compoundtheory.test.MyThrower").init();

        myThrower.myThrow();
    </cfscript>
    <cfcatch type="com.compoundtheory.test.myException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

The result that came from this was that 'java.lang.Exception' was output onto the screen.  This means that the ColdFusion <cfcatch> statement bypassed the 'com.compoundtheory.test.myException' type (which is its real type) and caught it at the 'java.lang.Exception' level, which is what 'myException' extends.

This led me to believe that the ColdFusion <cfcatch> can only catch exceptions that are loaded in its class path on start up.  To this effect I had two more test beds.

The first test was to get my JavaLoader loaded class to throw a 'java.io.IOException' - an exception that is native to Java 1.4, which comes with ColdFusion, and is loaded when ColdFusion starts.

The test bed looked like this:

<cftry>
    <cfscript>
        myThrower = jl.create("com.compoundtheory.test.MyThrower").init();

        myThrower.myThrowIOException();
    </cfscript>
    <cfcatch type="java.io.IOException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

In this case, 'full' was output, that meaning that the <cfcatch> was able to the exception with the type 'java.lang.IOException', just as it was meant to do.

The final test was when I moved my created classes into the ColdFusion class path, restarted the server, and ran my tests again.

The test bed now looked like this:

<cftry>
    <cfscript>
        myThrower = createObject("java", "com.compoundtheory.test.MyThrower").init();

        myThrower.myThrow();
    </cfscript>
    <cfcatch type="com.compoundtheory.test.myException">
        full
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="java.lang.Exception">
        java.lang.Exception
        <cfdump var="#cfcatch#">
    </cfcatch>
    <cfcatch type="any">
        any
        <cfdump var="#cfcatch#">
    </cfcatch>
</cftry>

In this case, the output was 'full', that meaning that the <cfcatch> could catch the custom exception, as it had been loaded with the ColdFusion library at start up.

So what does this all mean? Does it mean you can't use libraries with custom exceptions in them? No it does not.  But it does mean you need to handle them in a slightly different way when using JavaLoader.

The solution to this problem is to write code that looks like this:

<cfcatch type="java.lang.Exception">
    <cfswitch expression="#cfcatch.Type#">
    <cfcase value="com.compoundtheory.test.myException">
        <!--- do something with it --->
    </cfcase>
    <cfdefaultcase>
        <cfrethrow>
    </cfdefaultcase>
    </cfswitch>
</cfcatch>

The nice thing is that the 'type' attribute on the cfcatch variable will be set properly to the type of the Java Exception, so we can use it as a sort of 'filter' to weed out the Exceptions we wish to handle, and rethrow the ones that we don't.  It's not the prettiest thing in the world, but it works.

I'm not sure if I classify this as a bug in ColdFusion, but it definitely is an issue if you're not sure how to resolve it.
20 January 2007 10:17 AM 0 Comments

JavaLoader 0.3 - Oops! Missed the Readme.txt

Ooops! For those of you who were wondering where the readme.txt had gone to in JavaLoader, I accidentally left it off!

I just added it back into the zip file, so if you wanted it, you can re-download it. Sorry about that!

03 January 2007 08:59 PM 23 Comments

Javaloader Version 0.3 Released

I quietly released version 0.3 of JavaLoader today. I'm not sure if anyone actually noticed. Mind you, I didn't actually tell very many people, so I guess I should proclaim a little.

The main purpose of this release is to give greater control over the ClassPath loading behaviour. There are two new optional arguments on the JavaLoader library

loadColdFusionClassPath - this tells JavaLoader whether or not to load the ColdFusion Java libraries.

By default this is set to false.

This is a change from the previous JavaLoader, as it would load all the libraries associated with ColdFusion by default.

loadedClassPathBias - this tells JavaLoader to use a ClassLoader that searches the JAR libraries it has been passed, before it looks to the parent.

This is true by default.

This is also a change from the previous version of the JavaLoader library, which would automatically load the parent's classes before the JavaLoader classes.

This is particularly useful when ColdFusion classes are required, but you need to overload certain libraries that are loaded with ColdFusion.   

More details can be found in the readme.txt file inside the JavaLoader download .

For questions or comments, feel free to email me , fire off a message to the forum , or file a bug report .

01 December 2006 04:37 PM 10 Comments

JavaLoader – The Order in which Libraries are Loaded.

I realised something today, I've been telling something about the JavaLoader that isn't true.

By default, JavaLoader loads the ColdFusion class path as its parent when loading in custom Java libraries.

This means that if JavaLoader can't find a class that you are loading through it via the Jars that you have loaded, it will look to what ColdFusion has loaded to see if it can find it there.

I had always assumed that if you loaded something, say for example, the newer version of log4j with JavaLoader, for the Jars loaded with JavaLoader, they would see the newer version, rather than the older version of log4j with ColdFusion.

This is actually, completely and utterly false. I apologise for all the frustration I probably incurred on people for making this statement.

Reading the Java docs it explicitly says : 'When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.'

So this means that when looking for log4j - the one in ColdFusion actually takes precedence!

This makes sense in the Java world, as it allows for less confusion from the Java engine to be able to resolve classes - but from a ColdFusion perspective it makes life very difficult as we don't have the ability to modify what is loaded at application startup as we would if we had written a Java application from scratch.

A workaround for this is to pass Java null into the JavaLoader as a second variable like so:

loader = createObject("component", "JavaLoader").init(paths, JavaCast("null", ""));

This will create a JavaLoader that is not set with ColdFusion as the parent.

I am currently working on JavaLoader 0.3, that will make the precedence on the loaded classes that will solve this problem all up, as well as some parameters to avoid loading the ColdFusion classpath altogether, but I thought I would give people a heads up now to avoid frustration down the road.

04 September 2006 10:53 AM 0 Comments

AsyncHTTP 0.2 Released

Thanks to a Stefan (sorry, don't know your last name), and Rob Pilic who sent me emails about AsyncHTTP , there have been a couple of small enhancements / bug fixes made to this library.

The first solved a compatibility issue with CFMX 6.1.  This has been changed, and should mean that AsyncHTTP should now work on 6.1. (Cross Fingers)

The second involved some strange scenarios in which basic data was coming out of queries as strange data types, and was causing Java cast exceptions when doing post() requests.

Now the AsyncHTTP will automatically cast everything in the post formData argument to a String, which resolves this issue, and means there doesn't need to be any external JavaCast() calls on weird data.

That's pretty much it.

If anyone finds any other issues, please feel free to send me an email .   
19 July 2006 10:33 AM 6 Comments

AsyncHTTP - Asynchronous HTTP Requests

I don't know how many times I've gone looking to do asynchronous processing in ColdFusion, and come up against the myriad of hacks, workarounds and that general feeling that I want to poke my eyes out with a rusty spoon.

Now that JavaLoader exists, integrating Java with ColdFusion becomes so ridiculously easy, it would have been relative heresy if I hadn't sat down for an afternoon and wrote a library for making asynchronous HTTP GET and POST requests.

To use the asyncHTTP library , you simply have to drop /asyncHTTP/ the folder in your web root, or create a mapping to it.

From here we create an instance of the AsyncHTTP.cfc:

asyncHTTP = createObject("component", "asyncHTTP.AsyncHTTP").init();

Now that we have an instance of the AsynHTTP CFC, to do an asynchronous GET request, we simply call:

asyncHTTP.get("http://www.site.com/mytemplate.cfm?var=value");

If we want to pass form data across, we can also do an asynchronous POST request, like so:

formData = StructNew();
formData.var = "value";
asyncHTTP.post("http://www.site.com/anothertemplate.cfm", formData);


That is it! It is as simple as that.

Please download the library, give is a spin, and any questions, feedback, bugs or general comments, please either reply to this blog post, or shoot me an email .

22 June 2006 10:59 AM 3 Comments

JavaLoader 0.2 Released

Huge changes! Massive Changes! The whole thing has been rewritten!

Okay, I'm lying.  The only thing I changed is that if you pass in a path to a JAR or a directory when you init() the JavaLoader, it will throw an Exception if the path doesn't exist.

This is simply a useful addition for debugging purposes, especially if you are wondering why you can't load a particular class, or you are getting the wrong version of a class, if you are trying to overload a class that is loaded into ColdFusion.

Oh yeah, I added a 'getVersion()' method too.

If you have any questions, comments or bugs, please send me an email or respond to this blog post.
12 May 2006 04:20 PM 4 Comments

Running Python on ColdFusion

I have no idea why you would actually do this, but the fact that you can is super cool.

1st we download Jython , the Java implementation of Python

2nd we drop the jython.jar file in the same dir as the below code.

3rd we use the JavaLoader.cfc to load up the jar file. 

4th watch Python run in ColdFusion!

This is a CF translation of the Java embedding tutorial at http://www.jython.org/docs/embedding.html

<cfscript>
    //set he path
    paths = ArrayNew(1);
    paths[1] = expandPath("jython.jar");

    //create the loader
    loader = createObject("component", "JavaLoader").init(paths);

    //create the Python Iterpreter
    interp = loader.create("org.python.util.PythonInterpreter").init();
   
    //set standard output and errors out to the screen
    interp.setOut(getPageContext().getResponse().getOutputStream());
    interp.setErr(getPageContext().getResponse().getOutputStream());
   
    //top line
    writeoutput("Hello, brave new world <br/>");

    //do some python   
    interp.exec("import sys");
    interp.exec("print sys");
   
    pyInt = loader.create("org.python.core.PyInteger").init(42);
   
    interp.set("a", pyInt);
   
    //this now prints out to the screen!
    interp.exec("print a");
    interp.exec("x = 2+2");
   
    //get some values back out of python
    x = interp.get("x");
   
    writeoutput("x: " & x & "<br/>");
   
    writeoutput("Goodbye, cruel world <br/>");
</cfscript>

Okay, so I'm just hyped up about using the JavaLoader to do some weird and neat stuff - but hey, it's really cool, allright!

12 May 2006 02:38 PM 4 Comments

JavaLoader.cfc v0.1 Released (Loading Java from ColdFusion part 2)

Well, I *was* going to go to the gym, but noooo, I got pestered by a bunch of people to actually produce a generic version of my JavaLoader that I talked about in a previous blog post .  You people know who you are, and you should be ashamed.  Ashamed that you forced me to produce more open source code. Shame on you indeed.

Now that I've got all that drivel out, I've released a generic version of the Java Class loader for loading external JAR files.  Be they ones you created, an open source library, or a library you created to work with *another* jar library - all is possible with this tool.

The key features of this CFC are:

So, how do we use it? Well, there is an example in the download , but I'll give you a run down here.

Say we have a jar file, 'toolbox.jar', and we went and wrote our own code base and stored that in 'ourcode.jar' that referenced objects in toolbox.jar.

First we need to create an Array with the absolute file paths to each of these in it, so we would go:

paths = ArrayNew(1);
paths[1] = expandPath("toolbox.jar");
paths[2] = expandPath("ourcode.jar");

Then we create our JavaLoader, passing in the array, so it knows what to load -

loader = createObject("component", "JavaLoader").init(paths);

So now, we can create a instance of an object from ourcode.jar, say, for example the 'OurCode' class

If we were to just want to create a default (no arguments) instance of OurCode, we could now go:

ourcode = loader.create("OurCode").init();

Just like we would on a createObject("java", "OurCode").init() call, if we had access to the 'OurCode' class.

But say, for example, OurCode also had the option of taking an int and a String as an argument - we could now go:

ourcode = loader.create("OurCode").init(15, "I love Strings");

Again, same as we would on a createObject("java", "OurCode").init(15, "I love Strings") call, if we had access to the 'OurCode' class.

But what if we wanted to get complicated, I mean, we said that ourcode.jar referenced code in toolbox.jar, so maybe OurCode may want to take a ToolBox class instance as an argument - this is all possible.  We have loaded both JARs into the loader, so we can get to both instances, and we use CF to make the constructor work, like so:

toolbox = loader.create("ToolBox").init();
ourcode = loader.create("OurCode").init(toolbox);
 

Again, same as we would on a createObject("java", "OurCode").init(toolbox) call, if we had access to the 'OurCode', 'ToolBox' classes.

Oh, and I almost forgot, what if we want to access static methods, or values? Still the same thing as createObject - we just don't call an init() on the object we get on the create() call, like so -

Utils = loader.create("Utils");
resultFromStaticMethod = Utils.doThisThing("hello");

Again, same as we would on a createObject("java", "Utils") call, if we had access to the 'Utils' class.

That is actually it, in terms of using the JavaLoader, but this opens up a huge area of development where in theory you could actually write most of your object development in Java, and then just have the display tier in CF (I'm not advocating the idea, but you *could* do it), not to mention you now have access to almost every Java lib out there that doesn't require you to install anything J2EE, like a servlet etc - which is a very powerful thing.

Hope you all enjoy. Any questions or comments, either send me an email , or respond to the blog post. 

Details on the project can be found here.  

10 May 2006 11:28 AM 16 Comments

Running your own Java libraries in ColdFusion with style

I've been doing a ridiculous amount of work recently writing up some Java code that I am looking to deploy with Transfer, and in the process have had all sorts of fun running around exploring the internals of ColdFusion.

The issue however was being able to deploy the code with my library.

(As per usual with these posts, you must note that some of these methods are undocumented and liable to change, yadda ya)

I had my JAR file that I wanted to be able to use with my ColdFusion code, but there were several problems

   1. The Java code referenced some ColdFusion, and other related JAR files that were loaded into CF at startup
   2. Some of my objects I wanted to be able to create via CF have constructors that require arguments, which is tricky business.
   3. ColdFusion likes to keep a 'hold' on any Jar it loads up via URLClassLoader, so being able to redeploy/upgrade the code is tricky, as you can't delete the file without resetting the server.

Okay, so we'll start at the beginning - obviously we have the initial aspect of using a URLClassLoader to load in the external series of .class files, or .jar files, as Spike wrote about back in 2004 . (I'm not going to cover that aspect of it here, there is plenty of examples out now on how to use URLClassLoader out on the blogsphere)

This is all fine and dandy, I load in my class, and I try and create an instance, but it will throw an error - you know why? Because the code in my JAR references Java classes that the URLClassLoader doesn't know about.  Namely ColdFusion classes! So it throws a big fat hairy error as it can't see them.

Now, the neat thing is, a URLClassLoader's constructor can take a java.lang.ClassLoader as it's parent - which means it can look to it to try and resolve classes.  So off we run to get the ClassLoader for the ColdFusion context.

There are about half a dozen different ways of doing this, but I did it this way -

cfClassLoader = getClass().getClassLoader();


getClass() gets the java.lang.Class object of the current page or cfc, which is very handy for us, as we can grab the ClassLoader for the CF context, and thereby resolve classes that are loaded by ColdFusion when it starts up.

So now, when we create our URLClassLoader, we can create it like this:

classLoader = createObject("java", "java.net.URLClassLoader").init(URLs, getClass().getClassLoader());

Where URLs is the array of java.net.URL that we need to tell the URLClassLoader what directories and jar files to load in.

Okay, so that's all well and good, but problem number 2 arises.  URLClassLoader allows us to make calls like:

string = urlclassLoader.loadClass("java.lang.String).getInstance();

To create an instance of a Java object.  Which is all fine and dandy if there is a default constructor, BUT so often Java objects like to take arguments when they are instantiated.

I beat my head against this one for a while, as it is a real pain to try and do this through reflection - and then it dawned on me - ColdFusion has already done the hard work for us, why shouldn't we just take advantage?

So I did some digging around and worked out that when you write:

System = createObject("java", "java.lang.System");

The object 'System' is an instance of the coldfusion java object  'coldfusion.runtime.java.JavaProxy'.  The JavaProxy takes a java.lang.Class as an argument in it's constructor, and then handles all the aspects of interpreting CF calls on Java objects.

So now, when we load up a class we want an instance of in ColdFusion, we do this -

class = getClassLoader().loadClass("myPersonalJavaObject");
       
personalObject = createObject("java", "coldfusion.runtime.java.JavaProxy").init(class);

This gives us access to the object as we would normally through a createObject("java", "className"); call.

So now, as we would normally, if we want to create an instance of the object we can call -

instance = personalObject.init();

Just like we would normally.  But if we have arguments

instance = personalObject.init(myarg1, myarg2);

And ColdFusion will handle the aspect of translating the CF to the Java object for you.

Finally, the issue that, when you've made your URLClassLoader to a JAR file, the system often won't let you delete the file, as it still marks it as being 'under use'.  The way I solved that problem was by using ANT to add a datestamp to the name of my jar flie when it creates it.

This does 2 things:

   1. Gives the file a unique name, so I don't have to worry about deleting the previous JAR, and can do so when the server gets reset, or the garbage collector realises that nobody is using the JAR anymore, and releases it.
   2. Lets me know when looking at the dir where I store my JAR files which file was created first.

Since I know which one was created first - as long as I load the most recent JAR file to the URLClassLoader first, it will be the first one queried for the class files that are being requested, and therefore you can use the objects that you want.

It also means you could also write some nifty code to ignore the previous version by tokenizing the name of the file, but I will leave that aspect up to you.

This code has yet to be committed to the Transfer CVS repository, but assuming it all goes ahead as planned, look in the package transfer.com.util for a JavaClassLoader to see these techniques in action.

I hope that all made sense, and makes life easier for you while you write your own Java code to run alongside ColdFusion.