Running Javascript In ColdFusion With CFGroovy And Rhino

Posted November 30, 2009 at 8:51 AM by Ben Nadel

Tags: ColdFusion, Javascript / DHTML

As Barney Boisvert has demonstrated with his CFGroovy custom tags, scripting in Java is surprisingly easy. As he explains in the CFGroovy project, any scripting language that is JSR-223 compliant can be executed inside of a Java-based context with mostly-seamless communication between the Java context and the scripting context. The CFGroovy project was designed originally (I think) to work with Groovy; but, it can now be used run code through any JSR-223 compliant script engine implementation in your Java classpaths.

Because the set of available script engine implementations depends on your JRE, we need to ask Java to see what's available. We can get this information from the Javax script engine manager:

  • <!--- Get the script manager class. --->
  • <cfset scriptManager = createObject(
  • "java",
  • "javax.script.ScriptEngineManager"
  • ) />
  •  
  • <!--- Get the factories that are natively available. --->
  • <cfset scriptFactories = scriptManager.getEngineFactories() />
  •  
  • <!---
  • Loop over the factories and output the names that each
  • can build.
  • --->
  • <cfloop
  • index="scriptFactory"
  • array="#scriptFactories#">
  •  
  • <!--- Output factory name and version. --->
  • <cfoutput>
  • [
  • #scriptFactory.getEngineName()# -
  • #scriptFactory.getEngineVersion()#
  • ]
  •  
  • <br />
  •  
  • <!---
  • Output the names that this factory will respond to
  • (the names for which it can create valid script
  • engines).
  • --->
  • <cfloop
  • index="alias"
  • array="#scriptFactory.getNames()#">
  •  
  • - #alias#<br />
  •  
  • </cfloop>
  •  
  • </cfoutput>
  •  
  • </cfloop>

Here, we are asking the script engine manager for its factories, and then, from each factory, we ask it for the list of "names" for which it can create script engines. When we run the above code (on my personal JRE), we get the following output:

[ Mozilla Rhino - 1.6 release 2 ]
- js
- rhino
- JavaScript
- javascript
- ECMAScript
- ecmascript

As you can see, my script engine manager will respond to js, rhino, JavaScript, javascript, ECMAScript, and ecmascript. It is important to understand that I have not explicitly installed any Rhino package into my Java classpaths. It appears that Rhino's 1.6r2 implementation comes pre-packaged with the JDK 6 and JRE 6 libraries. It also appears that Rhino is the only script engine implementation that comes pre-packaged.

This is very cool! Now that we know that Rhino is packaged with the JRE, let's run some Javascript in ColdFusion using CFGroovy:

  • <!--- Import the CFGroovy tag library. --->
  • <cfimport prefix="g" taglib="../cfgroovy/" />
  •  
  • <!--- Execute Javascript (on the Server). --->
  • <g:script lang="JavaScript">
  •  
  • <!---
  • Create the super constructor for the Person class.
  • This will create an object with private variables
  • and getters / setters.
  •  
  • Not only will this test for object functionality, it will
  • test to make sure the concept of lexically-bound variables
  • remains true even inside the ColdFusion context.
  • --->
  • function Person( name ){
  • var _name = name;
  •  
  • return({
  • getName: function(){
  • return( _name );
  • },
  •  
  • setName: function( name ){
  • _name = name
  • return( this );
  • }
  • });
  • };
  •  
  •  
  • <!--- Create a new person. --->
  • var katie = Person( "Katie" );
  •  
  •  
  • <!---
  • Store a message value into the ColdFusion Variables
  • scope; this value is just a simple string.
  • --->
  • variables.put( "message", (katie.getName() + " is hot!") );
  •  
  • <!---
  • Store the new Person instance back into ColdFusion.
  • For this, we need to use the Java-native methods
  • calls for the Variable scope's hash table.
  • --->
  • variables.put( "katie", katie );
  •  
  • </g:script>
  •  
  •  
  • <!---
  • Output the message we stored. Since the original value is
  • a simple string, it has been automatically converted into
  • a Java string that we can use as-is.
  • --->
  • <cfoutput>
  • Message: #message#<br />
  • </cfoutput>
  •  
  •  
  • <!---
  • Now, that "katie" object is stored in the variables scope,
  • let's get the Name property. Unfortunately, the Java
  • representation of a JavaScript object is not exactly as it
  • is in Javascript - it's a simulation. As such, we need to
  • fenagle a bit to use the object in the ColdFusion context.
  • --->
  • <cfset name = katie.callMethod( katie, "getName", arrayNew( 1 ) ) />
  •  
  • <cfoutput>
  • Name: #name#<br />
  • </cfoutput>

Here, we have some Javascript code that defines a class, "Person," and instantiates it. Then, both the class instance and a simple message are stored back into the ColdFusion Variables scope. Notice that I can't simply use property-dot-notation (ex. variables.katie) to store values into the Variables scope - I have to use the Java-based put() method. While I don't demonstrate it, I would also have to use the get() method to gather information from the ColdFusion objects bound to the Javascript context.

When we run the above code, we get the following output:

Message: Katie is hot!
Name: Katie

Very cool! As you can see, simple values (such as strings) that are passed from the Javascript context to the ColdFusion context are easy to deal with. More complex objects, like Javascript class instances, are not so easy to deal with - they don't map directly to objects as we typically think of them; rather, they are the Java-based implementation of the Rhino-based Javascript object simulations.

What's very cool, though, is that even outside of the Javascript context, the Javascript methods are still lexically-bound. Meaning, the methods defined in the Person() pseudo constructor have access to all of the variables (ex. _name) that were also defined in the Person() local scope. This is one of the greatest features of Javascript and it's exciting to see that it hold true even after the Javascript objects leave the Javascript context.

I don't really know why I would want to run Javascript in ColdFusion, but it's pretty cool that I can for funzies. Take note, however, that Rhino does not offer a full simulation of Javascript; there is no sense of a Window or a Document object or anything else that is directly tied to a browser-based implementation of Javascript. Of course, that can be fudged, which I'll talk about in a later post.




Reader Comments

Nov 30, 2009 at 11:58 AM // reply »
25 Comments

Nice article, Ben. It's worth mentioning that you can run the non-DOM pieces of standard JS frameworks on the server-side without any fuss. I was doing this with the Prototype core back in the CFRhino days. So you can very easily use some of the tooling you use client side on the server.

Also, the Rhino implementation that ships with the JRE is not the full Rhino implementation. They've removed E4X support, specifically, along with a few other changes. Sun has published a list of things they've changed, but I'm not sure where that's available. However, if you want to use a different version of Rhino, you just have to drop the JAR on your classpath and you'll be set. And in fact, chances are good you're not using the Sun-packaged Rhino anyway; ColdFusion ships with at least two different versions of Rhino inside.


Nov 30, 2009 at 12:03 PM // reply »
11,238 Comments

@Barney,

Ah, good point; since I've only really used jQuery as my primary Javascript library, it didn't occur to me try anything else.

In my next post, I am going to cover what is needed to run full jQuery using John Resig's env.js project.... significantly more complicated than the above example. Ironically, it still uses CFGroovy since Groovy just makes it so much easier to create class loaders and other Java-like constructs.


Nov 30, 2009 at 5:07 PM // reply »
13 Comments

http://java.sun.com/javase/6/webnotes/

"E4X (ECMAScript for XML - ECMA Standard E4X) has been excluded. Attempting to use XML literals in JavaScript code will result in a syntax error. This feature depends on the XMLBeans library."

Great work Ben, one step closer to my dream of server-side JavaScript in a CF context :)


Dec 1, 2009 at 2:21 AM // reply »
1 Comments

@Marcel,

If you are interested if Javascript on CFML, check out the efforts of Alan Williamson getting that to work on Open BlueDragon. The ethos post here:

http://alan.blog-city.com/server_side_javascript_with_cfml.htm

You can get the OpenBD plugin here:

http://alan.blog-city.com/cfjs_alpha.htm


Dec 1, 2009 at 2:52 AM // reply »
13 Comments

@Peter thank you so much for that link! I had no idea there were others with my CFJS desire let alone one building it. I added a request for it to Railo's user voice site and not a single user other than a guy I work with voted for it!

Now if only it can be done on Railo too then there would be a clear reason for Adobe to build it into CF10 and then CFJS can take over the world! :)
(at least in my day dreams)


Dec 1, 2009 at 3:07 AM // reply »
2 Comments

@Marcel

I tried to vote for it - but I can't find it?


Dec 1, 2009 at 4:54 AM // reply »
13 Comments

@Joel
I had forgotten how ambiguous I had made it, I have added one a bit easier to find:
http://railo.uservoice.com/pages/21016-general/suggestions/402998-cfjs


Dec 1, 2009 at 5:15 AM // reply »
2 Comments

@Marcel,

Have voted - thanks

Joel


Dec 1, 2009 at 8:20 AM // reply »
11,238 Comments

A follow up to this post, this time executing jQuery on the ColdFusion server:

http://www.bennadel.com/blog/1767-Running-Javascript-And-jQuery-In-ColdFusion-With-CFGroovy-And-Rhino.htm


Dec 1, 2009 at 2:17 PM // reply »
33 Comments

That is absolutely sweetness man. I love JS.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools