Developer Week Slides and Code

Sorry for the delay in getting this posted. Here are the slides and the sample code from my ColdFusion Developer Week 2012 presentation; User Experience upgrade through HTML5 charts and videos.

The sample code does contain the sample videos as well so it is a bit large (45mb).

Download Sample Code

Till next time...

--Dave

ColdFusion Developer Week

In just a couple days begins ColdFusion Developer Week. Developer week is a full week of online sessions all about ColdFusion 10.

Yours truly will be speaking on HTML5 charts and video. While neither of these are new to ColdFusion 10 they did get a overhaul.

So, signup, attend a couple sessions, and build something great. Oh... and the best part... it is all FREE!

Here are the details....

ColdFusion Developer Week is happening between the 4th and 8th June.

With the launch of ColdFusion 10, we are back with the 2nd ColdFusion Developer Week, a series of free, live webinars hosted by seasoned ColdFusion experts. The webinars cover a wide range of topics, from what ColdFusion is and how to code it, to more in-depth topics related to CF10- HTML5, REST, ORM, Security enhancements and more.

If you are a new developer, someone with little or no ColdFusion experience, or even if you have been using ColdFusion all your life, these sessions are ideal for you. The ColdFusion Developer Week provides something for everyone so sign up now.

http://adobe.com/go/cfdeveloperweek

See you there...

--Dave

Application Security - Myth or Fact Slides

Here are the slides from my session at cf.Objective(). Unfortunately, I can't attach the demo app that I used during the presentation. If you have any questions please let me know.

Till next time...

--Dave

ColdFusion 10 released

Here is the obligatory blog about the release of the next version of ColdFusion 10. I have to say I am very excited about this release and the new features in it.

Go get it.. Go build something amazing.

www.coldfusion.com

Till next time,

--Dave

ORM Event Handling

This is probably not life altering news for most. However, after spending a couple hours tracking down how to do something I figured I would blog it. What I was trying to do was setup an preupdate and preinsert events on a specific entity. I have previously setup global events so I figured this would be a slam dunk.

But first, what are event handlers and what can you do with them? Well, think of them as database triggers. They could be used to log record updates, or even data loads for that matter. You can find a full list of them here:

http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSDD377092-70D9-4b11-A19C-505F59EE31D1.html

To use event handlers you first need to enable them in your application. This is accomplished by updating the orm settings in your application.cfc file. The eventhandler setting is required if you are using global events.

view plain print about
1this.ormsettings = {
2eventhandling= "true",
3eventhandler - "your.event.cfc"
4}

As an example, lets say we want to update an created date any time a record is inserted. Instead of going to all your code where the entity is created it makes much more sense to add an event handler.

view plain print about
1public void function preInsert(any entity){
2        var thisTable = getMetadata(arguments.entity).table;
3        if (thisTable == 'myTable'){
4            entity.setCreateDate(now());
5        }
6        
7    }

In the code example above we run a preInsert event. The code checks for the table being inserted into and if it is the correct table, the create date is set.

This works just fine but it probably not a good candidate for a global event. This is more something that should be on the specific entity. This can be done by adding that same function, with some slight modifications, to the persistant cfc for the table.

view plain print about
1public void function preInsert(){
2        this.setCreateDate(now());
3    }

This is the part that tripped me up. The function is about the same with the exception of the arguments. Notice that for the entity specific function there are none. Also, to set the create date we use the "this" scope. The documentation from Adobe on event handlers gives poor, or non-existant examples of event handlers. So, trial and error, and google helped me figure this out.

So there you have it, when dealing with global events you need to reference the arguments scope when dealing with the entity. But, when dealing with a specific entity the "this" scope is utilized.

Update:

The great John Whish pointed out a couple other ways to accomplish this as well. Apparently the "this" scope is not necessary. You can also sit it without using the set method. I tried both of these and they worked just fine.

view plain print about
1public void function preInsert(){
2        setCreateDate(now());
3    }
4
5    public void function preInsert(){
6        variables.CreateDate = now();
7    }

Till next time,

--Dave

Websockets demo: Log Watcher

So, I really wanted to create a demo for websockets that was not the norm. I wanted to try something that was more of a "what could I really do with with this" demo. After bouncing around a few ideas I finally settled on this, Log Watcher.

How many times have you wished you could tail a log file on your remote ColdFusion server? How many times have you remoted into your server to tail a log? If you are anything like me (probably not but for arguments sake lets say you are) you have probably done it once this week. At the very least once in the past few weeks.

What is log tailing? Well, to sum up it is viewing a log file as new lines are written to the file. This can be accomplished on unix using "tail -f {log}" or using something like BareTail on windows.

Now, what if you didn't have to remote into the server to tail the log? This is where Log Watcher comes in. Log Watcher allows you to tail a log via a web browser. This low overhead app does the same thing as a server based tail but with a little more flare.

So, how does it work? Well, it is all made possible due to ColdFusion 10. The interface is a simple browser app using Bootstrap for the pretty (I don't do pretty). The real guts of the app is on the server. Here, threading is used and a couple java objects to do a constant read on a file. The data (rows) from the log file are pushed to the client using websockets.

To accomplish this there are a few things I had to overcome. First was dealing with thread management. Creating threads that are designed to run forever is not something you generally want to do in a browser based application. This turned out be one of the more challenging parts. But this became infinitely easier thanks to a new setting in ColdFusion 10 to set the timeout to none.

view plain print about
1<cfsetting requesttimeout="0">

Next was dealing with the display and that all logs are not created equal. Then there was the issue of the app crashing the ColdFusion server (more on this later). A lot of trial and error went into building a way to display the log rows effectively. Once I solved these issues I was off to the races.

The client portion of the app is very basic. The only coolness there is the tiny amount of code for the client to subscribe to a web socket. Now, thanks to how websockets were implemented this results to just one tag

view plain print about
1<cfwebsocket name="lrbase" onmessage="wsFunctions.mycbHandler" subscribeto="lrbase"/>

This one little tag brings in all the necessary bits to do websockets. All we have to put in is the name of the websocket (as defined in applicaiton.cfc), the message handler, and the name of the channel to auto subscribe to on load.

Then just a little javascript to process the incoming messages. Here I handle the incoming data and split it up so I can display the data in a table. Name spacing my javascript has become a little habit. I don't do it all the time, but I find it useful when I want to encapsulate some code.

view plain print about
1var wsFunctions = (function() {
2
3    var wsResponsProcessor = function(obj){ // handle responses from WS
4
5        if (obj.type == 'data'){
6            
7            $('#mainContent2').show();            
8            output = splitMessage(obj.data);            
9            if (rowOut == 1 && useTableFormat(currentLog)){
10                    $('#headerRow').html(output);
11            
12            } else {
13            
14                if (loadDirection == 1){
15                    $(document).scrollTop($(document).height());                         
16                    $('#contentTable').append('<tr><td>'+rowOut+'</td>'+output+'</tr>');
17                } else {
18                    $('#contentTable').prepend('<tr><td>'+rowOut+'</td>'+output+'</tr>');
19                }    
20            }
21            rowOut++;
22        }    
23     
24 }
25    
26    return {
27        
28        mycbHandler: function(aEvent){
29         wsResponsProcessor(aEvent);
30        }
31    };    
32})();

To sum up all this javascript. If the type is "data" it processes the message. It is possible for the message to be other types for example the response message when subscribing. The message is then passed of to the splitMessage function. This function handles splitting the message into columns if the log is formatted that way. Then depending on load direction the row is either appended or prepended to the display.

To get the ball rolling there is a click handler on the log list. This processed the selected log and makes a ajax call to the server.

The logLoader.cfm does a few things. First, it includes the kill.cfm file. This file runs and sets a server var that any currently running thread will see and cause the thread to terminate. We then sleep the call for 1.5 seconds to give any other thread a chance to terminate. We then create the thread name and call the thread component.

The thread component is where the "magic" happens. This is where the thread is created and starts reading the requested log file.

view plain print about
1<cffunction name="readLog" access="public">
2        <cfargument name="threadName" type="string" required="true" />
3        <cfargument name="log" type="string" required="true" />
4        <cfargument name="channel" type="string" required="true" />
5        
6        
7        <cfthread action="run" name="#arguments.threadName#" logfile="#arguments.log#" channel="#arguments.channel#">
8        
9            <cfset server.channels["#attributes.channel#"] = thread.name>
10            <cfsetting requesttimeout="0">
11            <cfscript>                
12                FileName = "#server.logbase#/#attributes.logfile#.log";
13                FileIOClass = createObject("java", "java.io.FileReader");
14                FileIO = FileIOClass.init(FileName);                
15                LineIOClass = createObject("java", "java.io.BufferedReader");
16                LineIO = LineIOClass.init(FileIO);
17            
</cfscript>
18            <cfloop condition="1 eq 1">
19                <cfif server.channels["#attributes.channel#"] is not thread.name>
20                    <cfexit>
21                </cfif>        
22                
23                <cfset CurrLine = LineIO.readLine()>
24                
25                <cfif IsDefined("CurrLine")>                    
26                    <!---send websocket message--->
27                    <cfset wspublish("lrbase.#attributes.channel#", CurrLine)>
28                <cfelse>        
29                    <cfthread action="sleep" duration="1000" / >
30                </cfif>
31                    
32            </cfloop>
33        </cfthread>
34    </cffunction>

Walking through the function the first thing is does is create a thread with an action of run. This will create a running thread that will be come "detached" from the request that created it. First a server var is set with this threads name and then the timeout is set to 0 (infinity). Next a couple java objects are utilized to read the file. This will allow for a non-blocking read on the file. This type if read is desired so that the system can still write to the file while it is being read.

Next a loop is created that has a condition that will never end. Then in the loop a check is made to see if the server var for the active thread matches the current thread. If not the loop will exit thus also ending the thread. Next a line in the file is read. This will always read the next unread line. So, it will start at line 1 and get the next line on every loop. Eventually the currline var will not be defined. This is because the whole file is read. If the var is defined a websocket message is published to the channel for the app. This will magically make it back to the client and displayed.

Now, if the currline var is undefined the thread is put to sleep for a second. This is here because this is where the ColdFusion server was crashing. Not putting the sleep here caused CF to spike the processor up to 100% and eventually die. After some trial and error the 1 second sleep seemed to be the sweet spot. Now the thread was never over 2% cpu load.

As the loop continues over time any new line written to the file will be picked up and processed.

So there you have it. You can download the code (attached to this post) and check it out. Just unzip the code and drop it into your web root for ColdFusion 10.

Till next time...

--Dave

CFSelenium auto start w/ output capture

In recent work I was investigating the possibilities of testing a system that was not necessarily built to support unit tests. The system is lacking any true component structure that would allow MXUnit tests to be created against the code. This is where Selenium comes in. After some investigation I figured out that I could use Selenium to test the system. Then taking it a step further I could then use CFSelenium with MXUnit.

In the event you didn't know, CFSelenium (http://www.silverwareconsulting.com/index.cfm/2011/2/22/Introducing-CFSelenium--A-Native-ColdFusion-Client-Library-for-SeleniumRC) is a ColdFusion wrapper to run Selenium Server. This will allow you to run Selenium tests without the need to use the Selenium IDE. Also, since we are writing tests in ColdFusion, we can add dynamics and other things to better exercise the interface. We can then wrap the tests in MXUnit test cases for a complete well rounded experience. My first exercise was I wanted to be able to auto start and stop the Selenium engine for each test suite. I didn't want to have the Selenium engine always running in a console on the server. Thankfully, CFSelenium comes with a way to do that. Here is a basic MXUnit test that is using CFSelenium.

view plain print about
1component extends="cfselenium.CFSeleniumTestCase" displayName="Untitled" {
2
3 public void function beforeTests() {
4 browserUrl = "http://www.google.com";
5 super.beforeTests();
6 selenium.setTimeout(30000);
7 }
8    
9    public void function testUntitled() {
10     selenium.open("/");
11 selenium.waitForPageToLoad("30000");
12 }
13
14    function afterTests() {
15     super.afterTests();
16 }
17}

As you can see we extend to the CFSeleniumTestCase. This gives us some base controls for CFSelenium. Mostly the before and after tests functions for CFSelenium. Now, don't get them confused with the beforeTests() and afterTests() functions in MXUnit.

In our MXUnit test we run beforeTests(). This then runs super.beforeTests(). This is the function in the CFSelenium cfc. This function basically creates the CFSelenium object and starts the Selenium server if it is not running.

Looking at the server.cfc file in the cfselenium directory, there is a startserver function. Here I made a slight modification to how the Selenium server actually starts. Granted I didn't have to modify it but I wanted to add some new functionality that wasn't possible using cfexecute.

Here is the original code

view plain print about
1<cfexecute name="java" arguments="#args#"/>

Here is my change:

view plain print about
1<!--- Get Java's runtime object which lets us execute system commands. --->
2<cfset runtime = createObject("java", java.lang.Runtime").getRuntime()>            
3<!--- Execute the command. --->
4<cfset process = runtime.exec(args)>

Now that I had Selenium server running in this fashion, I could add a little more functionality to it. Now, after the runtime.exec() command I added the following code

This allows me to capture the output that would normally be seen in the console. Since the errors come back in a different stream I have to create a second thread to capture those. There is no need to write any code to terminate the threads. These threads will end on their own when the Selenium server stops.

Lastly I create the ProcessStream function to do something with the stream.

view plain print about
1<cffunction name="processStream">
2    <cfargument name="catpureThread" type="any">
3    <cfset streamReader = createObject("java", "java.io.InputStreamReader").init(arguments.catpureThread)>
4    <cfset buffererdReader = createObject("java", "java.io.BufferedReader").init(streamReader)>
5    
6    <cfloop condition="true">
7    
8        <cfset line = buffererdReader.readLine()>
9    
10        <cfif not isDefined("line")>
11            <cfbreak>
12        </cfif>
13    
14     <cfset logStatus( text="-- #line#" )/>
15    
16    </cfloop>
17    
18</cffunction>

This uses some java objects to capture the thread output stream. The loop will continue forever continuously reading line after line of the stream. The loop will eventually stop once the buffer reader stops returning. This would happen when Selenium server stops. I then take the line output and use the pre-existing logStatus function to write it to the log. This now allows me to see the raw output from Selenium. This allows me to investigate any issues with the tests as well as look for any other issues.

Till next time,

--Dave

ColdFusion 10 WebSocket Demo App

So,

Websockets what are they? Here is what wikipedia had to say on the subject http://en.wikipedia.org/wiki/WebSocket. Basically put, websockets let you do a server "push" to a client browser.

If you have ever used BlazeDs you will be familiar with this type of technology. However with BlazeDS there was a constant open connection to the server. With websockets there is no persistant open connection. This greatly reduces overall overhead for both the client and the server.

So, what can you build with websockets? Well lots of stuff, you can create the obligatory chat client. Maybe an ad system that feeds new ads to a client. Maybe even a game where 2 people can play against each other.

Well, I figured it would be better just to build something to demo its features then to just talk about it. So, with that, I made a game. It is a 2 player game that allows people to play against each other in the same fashion as Battleship.

The downloadable code is attached to this post. A couple notes about the code. To run it effectively you need to open 2 browsers, not to browser windows. Also, I didn't to an exhaustive amount of testing on the app. If you just use it as intended it should work just fine. Also, if you have a console (firebug, or Developer Tools) running you can see the messages passed back and forth. In the base.js file at the very bottom uncomment the console.log line to see the output. Take a look at the code. Use it as an example to build your own next great thing. Let me know if you have any issues, questions or comments. I will do my best to assist as much as possible.

Till Next time...

--Dave

ColdFusion 10 and Builder 2.01 Public Beta

Yea.. title just about covers it. So... Go get it and check out all the new hotness. There are many new things to talk about and use. Here is a short list of the features that interest me the most.

  • Websockets
  • Switch from jRun to Tomcat
  • Rest web services
  • Security enhancements
  • Charting
  • Scheduler
  • Hotfix updater

http://labs.adobe.com/technologies/coldfusion10/

Go get it for your self. Come up with your own list. Build something awesome.

Till next time...

--Dave

My new adventure

Well,

For those of you not listening to the podcast, www.cfhour.com, after many years at Disney I decided to change jobs. Leaving Disney was not a decision I took lightly. The decision process caused many sleepless nights and many moments of panic. But with the help of family and friends I was, obviously, able to make a final decision.

I have to say, leaving somewhere you have been for just shy of 11 years is tough. There is nothing that can prepare you for that day you resign nor the last day at work. I wish all the best to those friends I left behind at Disney. I know they will go forth and blaze a path on on their own.

So, what am I doing now? Well, I am now a Sr. Developer at Nonfat Media. I am very excited about the future and what lies ahead. It is a strange place to be at the moment. I am coming from somewhere where I had all the answers to somewhere I have to ask all the questions. Once I get my bearings and get some knowledge I know I will be able to help do great things here.

So, what about my blog (haven't blogged in a while) and the podcast? They will both continue on. I have gotten permission to talk and blog about things that I do here (with some restrictions). So, I hope that along my new journey of learning I will be able to teach others as well.

Till next time...

--Dave

Previous Entries / More Entries