Websockets and the vanishing scopes, Part 2

Yesterday I blogged about an issue I was having with Websockets and scopes vanishing. After some comments to the post and subsequent messages on the FW\1 Google group I decided to do a little more testing. I was trying to see under what condition were the scopes being lost.

Initial test.

First step was to have an application.cfc setup with a websocket channel.

Application.cfc content:

view plain print about
1component {
3    this.name = "wstesting";
4    this.wschannels = [{name:"wstest"}];
5    this.sessionmanagement = true;
6    this.sessiontimeout = CreateTimeSpan(0,2,0,0);

Next up is the cfm files. These 2 blocks of code would go into separate files.

First the file to receive messages (receive.cfm):

view plain print about
1<script language="JavaScript">
2    function myHandler(msg){
3        console.dir(msg);
4    }    
7<cfwebsocket name="myws" onmessage="myHandler" subscribeto="wstest">

Then the file to send a message (send.cfm):

view plain print about
2    writeDump(var: cgi, label: 'cgi before');
3    writeDump(var: session, label: 'session before');
4    wsPublish("wstest",'my message');
5    writeOutput("<hr>");
6    writeDump(var: cgi, label: 'cgi before');
7    writeDump(var: session, label: 'session before');

So, to set it all up. Create the 3 files. First call the receive.cfm in a browser. Then in a new browser window call the send.cfm.

What you should see is that the session dumps are the same before and after. However, the cgi dump is different. The cgi dump is all based of the wspublish call and not the original request. However, the session scope is left untouched.

Now, lets make some modifications to do the same test inside a Framework One application. If you are unfamiliar with FW\1 then some of this may not make sense. But if you are you should be able to follow along.

First, modify the the application.cfc to extend the framework. Also, add a before and after function to the app.cfc that contain the scope dumps.

view plain print about
1function before( rc ) {
2    writeDump(var: request, label: 'request before');
3    writeDump(var: cgi, label: 'cgi before');
4    writeDump(var: session, label: 'session before');
8function after ( rc ) {
9    writeDump(var: request, label: 'request after');
10    writeDump(var: cgi, label: 'cgi after');
11    writeDump(var: session, label: 'session after');            

Next create a view for the send and receive. In the receive put in the same code as the first example. The send view can be an empty file.

In the controller that would be called for the send just do a simple wspublish.

view plain print about
1public void function send( rc ) {
2    wsPublish("wstest", 'something');

Now, that you have all that setup lets run the code. Just like before, first call the receive code. You should see 6 dumps that all mirror each other. Next call the send. This should throw an error. You should have 5 dumps and then the error. Take careful note of the dumps. The request dump in the after is all but gone except for one value. The CGI scope is redone just like the first example.

Now the odd part. The error that is thrown should state that "Variable SESSION is undefined."

For fun, go into the controller and remove the wspublish line. Then call the send again. This time the dumps should all work without error.

So there you go. While this doesn't correct the issue it at least gives more insite as to what is going on.

Till next time...


Websockets and the vanishing scopes

I have been working on a new application in FW\1. This application has a messaging aspect to it that sends alerts to users. The alerts can be either on screen, email, or a websocket message. When I went to start adding the websocket parts I started running into strange errors.

First, I was getting the following error after sending a websocket message and trying to do a redirect in FW\1.

The code looks like this (just a couple relevant parts)

view plain print about
1getmessengerService().sendMessage(message: "Message goes here", type: "error", delivery: 2);
2variables.fw.redirect('home:main.default', "displayMessage");

Original exception in onRequest
Cannot lock session scope.
Cannot use cflock to lock the application or session shared scopes without these scopes using the cfapplication tag. To use the session scope, you must enable session management. Application and/or Session variables must also be enabled in the ColdFusion Administrator. (Lock)

This struck me as odd because on refresh, I still had a session and was still logged in. I checked the redirect code and removed the preserve item (2nd argument) and tried again. This time I received a different error:

File not found: /Users/dferguson/Documents/Development/nfmtools/common/config/handler.cfc/Users/dferguson/Documents/Development/nfmtools/common/config/handler.cfc

Now I was totally lost. The redirect was going to a very odd place. However, the odd place it was going to was to not as odd as it seems. It was the defined handler for the websocket channel. So, I then decided to take out the handler and see how that would affect it. I now received this error:

File not found: /Applications/ColdFusion10/cfusion/wwwroot/CFIDE/websocket/ChannelListener.cfc/Applications/ColdFusion10/cfusion/wwwroot/CFIDE/websocket/ChannelListener.cfc

This is the default system handler for websockets. So, now I am totally confused and resting my head on my desk... over and over. I can't seem to get around these errors. Also, if I take out the wspublish() code everything works just fine. I even went as far as to put an application.cfc file in the directory with the handler to see if that did anything. Well... it didn't.

At this point I went in and started using the line debugger. If you have never used this tool then you are missing out. Instead of putting dumps and traces in your code you can actually watch the path that CF it taking through the code and what vars are being set. You can also see what is being passed to functions. So, I added a few breakpoints and ran the debugger.


Hashing files and Java heap space

So, for those that did not know. The hash() function in ColdFusion can do a cool trick. It can generate a md5 hash of a file. Why would you want to do this? Well, if you want to compare 2 files at the byte level a hash is the best way. IF the files are identical byte for byte the hash will be the same. if one byte in the file changed the hash changes. The change could be something as simple as changing a file attribute or an update to its last modified date.

Here is the code to do it. It is very simple.

view plain print about
1<cfset fileHash = hash(FileRead(myfullFilePath), 'MD5')>
This code would result in something that looks like this: 6168f305888c3d795e67c6de17bf8a21

This works perfectly in about 90+% of all cases. However, in what I was doing it worked in about 5% of all cases. The simple fact is that I was trying to hash files that were in the 250mb+ range. When doing this my server would start generating this lovely error:

view plain print about
1"Error","Thread-26","12/29/09","15:27:48",,"Error invoking CFC for gateway ProcessFile: Java heap space."
2java.lang.OutOfMemoryError: Java heap space
3    at java.util.Arrays.copyOfRange(Arrays.java:3209)
4    at java.lang.String.<init>(String.java:216)
5    at java.lang.StringBuffer.toString(StringBuffer.java:585)
6    at coldfusion.tagext.io.FileUtils.readFile(FileUtils.java:174)

I have not been able to determine the exact file size that causes this. I have seen it with files as small at 50mb. But, I do see it very regularly with files over 100mb. I have also not found a way around it yet. I currently just wrap the code inside a cftry to suppress the error.

Till next time...


Insufficient system resources; huh???

While working on a project to integrated Adobe LiveCycle and ColdFusion I ran into an odd issue. I was calling a LiveCycle service that returns a PDF document. That document is then written to the file system and then delivered to the client.

Everything was working fine then I started getting a strange error.

view plain print about
2 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
3 faultSubcode:
4 faultString: coldfusion.xml.rpc.CFCInvocationException:
5 [coldfusion.tagext.io.FileTag$SingleFileOperationException : An error occurred when performing a file operation write on file \\serverpath\tempMarkup\C1E254134EE109A1D312B01C5A2F7EFA.pdf.][java.io.IOException : Insufficient system resources exist to complete the requested service]
6 faultActor:
7 faultNode:
8 faultDetail:
9 {http://xml.apache.org/axis/}stackTrace:coldfusion.xml.rpc.CFCInvocationException: [coldfusion.tagext.io.FileTag$SingleFileOperationException : An error occurred when performing a file operation write on file \\serverpath\tempMarkup\C1E254134EE109A1D312B01C5A2F7EFA.pdf.][java.io.IOException : Insufficient system resources exist to complete the requested service]
10 at coldfusion.xml.rpc.CFComponentSkeleton.__createCFCInvocationException(CFCo... ''

This error would happen directly after the web service ran at the point where the file would be written. What was actually written was a zero (0) byte file and an error message was displayed. I was sure that the error was not in the web service as the error was after the service ran and returned. But at the same time the error said it was an AxisFault which usually points to web services.

After doing some trial and error, contacting a few people that may have a solution, praying, and doing a quick chant I was able to figure it out. I changed the code to write the file locally then move it to the shared storage. (Notice the UNC path in the error message?).

I have no idea why this threw this error as I was able to move the file from local to remote. I have a feeling it has something to do with Windows and it's ability to write the file to the remote storage.

till next time,