Thursday, January 8, 2009

Eclipse Annoyance

I truely appreciate eclipse as the ide for CF development. I've had a slight annoyance with it though since recently moving to a linux dev environment. In short, everytime I did a text search.... I would get an annoying little error box popping up saying:



Looking at the details of the error... I see the following:
"resource is out of sync with the file system"

After digging around a bit on google I found that this generally occurs when a file is changed/added outside of eclipse and it has, just as the error states, become out of sync with the file system. The solution is to refresh the project so that it picks up the changed/new files. If outside processes frequently change files outside of your eclipse, you can have eclipse automatically refresh the project by going to Window > Preferences and in General > Workspace. Check the box that says "Refresh Automatically". We use the fusebox framework which compiles the code into the parsed folder. So in development mode, the parsed folder has changed/new files all the time.

Well... I made this change and it still didn't work for me. I don't know if its something unique with linux or just a bug or what, but refreshing the parsed folder and setting refresh automatically did absolutely nothing to resolve the issue.

Then I had a duh moment. For my text search, I have it search in a working set. Why don't I just exclude the parsed folder from the working set. I don't really need to look in the parsed folder anyway. Sheesh, sometimes we can make things way harder than they need to be. So... Search > File... (or Cntrl-H for me) Then on the "Working set:" line, click "Choose...". I'm working with "Selected Working Sets". I edited my working set and under the "Working set contents" area I drilled down to the parsed folder in the relavent resource and unchecked it. Bingo... no more errors.

Hope this helps...
God Bless

Friday, September 26, 2008

Coldspring stopped me cold..

We just recently upgraded to Coldspring 1.2 and it wasn't long before I came to a grinding halt the next time that I needed to restart my CF instance. I got the following error:

Object Instantiation Exception
An exception occurred when instantiating a Java object.
The class must not be an interface or an abstract class. Error: ''.

The error occurred in C:\websites\coldspring\beans\AbstractBeanFactory.cfc: line 253
Our beta system wasn't having the same issues, so I decided to look at what might be different in the two environments. I found that I was still on 8.0.0 (doh!). So I went to http://kb.adobe.com/selfservice/viewContent.do?externalId=kb403277&sliceId=1 and upgraded.

That worked right? Wrong! Though it was good for me to get up to speed with the proper version, it did nothing in getting me back to productivity. I browsed some more on some blogs with pieces of the error message and came across a blog that seemed to think this error happend when some nulls were being thrown around when it expected actual values. I looked at this line in the loadFrameworkProperties method in Coldspring/beans/AbstractBeanFactory.cfc:

<cfset local.fileStream = CreateObject('java', 'java.io.FileInputStream').init(arguments.propertiesFile) />
... which caused me to look in the initial code or the AbstractBeanFactory.cfc file here:
<!--- ColdSpring Framework Properties --->
<cfset variables.instanceData.frameworkPropertiesFile
= "/coldspring/frameworkProperties.properties" />
<cfset variables.instanceData.frameworkProperties
= loadFrameworkProperties(ExpandPath(variables.instanceData.frameworkPropertiesFile)) />
So I looked for the .properties file in the /coldspring directory and found nodda. I plugged an empty file into the coldspring directory by the name of frameworkProperties.properties and I was back in business.

Hope this helps.

Blessings...

Tuesday, September 23, 2008

I shot the session...

I was reading across a couple of old blogs recently about the need to kill a session immediately rather than waiting for it to timeout. If you are using J2EE sessions, the session will be orphaned when the browser is closed but the session still lives on until it eventually times out according to the time set for your application. There may be a need to clear out some of those sessions when you're sure they are orphans. Maybe you have a user that is logging in from another workstation and would like to clear out the other session so that you don't have the same user logged in twice. Whatever your reason, there is a way to immediately clear out the session and still have the onSessionEnd execute in your Application.cfc. Try this little piece of code:
<!--- get the session id by working with the session tracker --->
<cfset _sessionid = '74306b9b10b4c354a8db101f73246434611b'/>
<cfset killSession(application.applicationname,_sessionid)/>

<cffunction name="killSession" output="false"
access="public" returntype="void">
<cfargument name="appName" required="true" type="string" />
<cfargument name="sessionid" required="true" type="string" />

<cfset var st =
createobject("java","coldfusion.runtime.SessionTracker") />
<cfset st.cleanUp(arguments.appName,arguments.sessionid) />

</cffunction>

If you do not have J2EE sessions enabled, you can call cleanUp(application.applicationName, _cfid, _cftoken).
Note: I haven't tested this one yet.


This will successfully remove that session. It will also execute any onSessionEnd code that you have to take care of any cleanup scripts that you have. This is an undocumented method of sessionTracker so use with caution knowing that things could change. I'm not sure if this works in versions before CF8. I would be interested in knowing, if someone would be so kind as to test it.

Blessings...

Monday, September 22, 2008

Undocumented Goodness

In working on a project the other day, I needed to allow users to interact with data in such a way that they were not tripping over each other. This led me down the path toward a proof of concept with monitoring sessions for a particular application. The problem is that when you "touch" the sessionScope methods it will reset the session timeout and keep dead sessions alive. This can be countered by calling the methods using reflection like so:
<cfset tracker=createObject("java","coldfusion.runtime.SessionTracker")>
<cfset sessions=tracker.getSessionCollection(application.applicationname)>
<cfoutput>
<cfloop item="loopSession" collection="#sessions#">
Idle Time:
#getSessionProxy(sessions[loopsession],'getTimeSinceLastAccess')#<br/>
</cfloop>
</cfoutput>

<cffunction name="getSessionProxy"
output="false" access="public" returntype="string">

<cfargument name="session" required="true" type="struct" />
<cfargument name="method" required="true" type="string" />

<cfset var _a = arrayNew(1)/>
<cfset var _sessionClass =
_a.getClass().forName("coldfusion.runtime.SessionScope") />

<cfset var _method = ''/>
<cfset var _value = ''/>
<cftry>
<cfset _method =
_sessionClass.getMethod(arguments.method, _a) />
<cfset _value = _method.invoke(arguments.session, _a)/>
<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn _value />
</cffunction>

That works great and is very valuable data, but what if you need to find out what the session.idofuser is on one of those sessions or another session variable that you need access too? There really is no reflected function that gives you access to those variables without touching the session timeout. You could do sessions[loopSession].idofuser but that would trip the session. Even a cfdump of the sessions collection trips the session. I couldn't find this documented on blogs or anywhere else, but there is a new sessionScope method going by the name of "getValueWIthoutChange". This must be new in CF8. I'm guessing one reason it was added is for the server monitor which gives you access to this info without touching the session timeout. If you google this method, you get absolutely 0 results. When I saw that in the dump of the sessionScope class, I knew there was hope. Important to note too is that Java is very case sensitive. Notice that the W and I are capped in "WIthout". Typo that made it through? Anywho, my next challange was finding the correct casting and such to be able to pass a var into the reflected getValueWIthoutChange method from CF. I flailed on this for about a day before I took this to a co-worker that was a java guy in a past life. He had it nailed down for me in a 1/2 hour or so. Long story short, we ended up with a method that will allow you to get any session var without touching the sessions. This is a beautiful thing and opens up all kinds of possibilities.
<cfset tracker=createObject("java","coldfusion.runtime.SessionTracker")>
<cfset sessions=tracker.getSessionCollection(application.applicationname)>
<cfoutput>
<cfloop item="loopSession" collection="#sessions#">
Idle Time:
#getSessionProxy(sessions[loopsession],'getTimeSinceLastAccess')#<br/>
User ID:
#getSessionValue(sessions[loopsession],'idofuser')#<br/><br/>
</cfloop>
</cfoutput>
<cffunction name="getSessionValue"
output="false" access="public" returntype="any">
<cfargument name="session" required="true" type="struct" />
<cfargument name="key" required="true" type="string" />

<cfset var a = arrayNew(1)/>
<cfset var valueMethod = ''/>
<cfset var value = ''/>
<cfset var sessionClass =
a.getClass().forName("coldfusion.runtime.SessionScope") />

<cftry>
<cfset a[1] =
CreateObject("java","java.lang.String").GetClass()/>
<cfset valueMethod =
sessionClass.getMethod("getValueWIthoutChange",a) />
<cfset a[1] =
CreateObject("java","java.lang.String").Init(arguments.key)/>
<cfif findnocase(arguments.key,structkeylist(arguments.session))>
<cfset value = valueMethod.invoke(arguments.session, a)/>
<cfelse>
<cfset value = ''/>
</cfif>

<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn value />
</cffunction>
<cffunction name="getSessionProxy"
output="false" access="public" returntype="string">

<cfargument name="session" required="true" type="struct" />
<cfargument name="method" required="true" type="string" />

<cfset var _a = arrayNew(1)/>
<cfset var _sessionClass =
_a.getClass().forName("coldfusion.runtime.SessionScope") />

<cfset var _method = ''/>
<cfset var _value = ''/>
<cftry>
<cfset _method =
_sessionClass.getMethod(arguments.method, _a) />
<cfset _value = _method.invoke(arguments.session, _a)/>
<cfcatch><!--- Do Nothing ---></cfcatch>
</cftry>
<cfreturn _value />
</cffunction>

Now, as an important note and as has been echoed on other blogs, this is an undocumented method and the farm should not be bet on it. There is no guarantee that it will live on in other versions of CF so use wisely.

With that said, praise God for technology and go change the world.

Blessings...

Friday, September 12, 2008

RegEx broke my phone

We had a bug turned in on a form that was not accepting valid phone numbers, or so it seemed. The number used was something like 233-122-2323. Looks like a valid phone number right? I dug into the form field and found that it was a cfinput tag utilizing the validate="telephone". We recently moved to CF8 and I was wondering if this was a CF8 issue that was somehow unique. I looked at the generated source in order to evaluate the resulting js that is used to validate the form on submit. That led me to this code:

//form element phone 'TELEPHONE' validation checks
if (!_CF_checkphone(_CF_this['phone'].value, true))
{
alert(_CF_this['phone'].value)
_CF_onError(_CF_this, "phone", _CF_this['phone'].value, "A valid phone number is required.");
_CF_error_exists = true;
}
We can find the code for _CF_checkphone buried in this file, depending on your instance:
\JRUN4\servers\[instance]\cfusion-ear\cfusion-war\CFIDE\scripts\cfform.js
Finding the function in this file revealed the regular expression that is being used to validate phone number.

/^(((1))?[,\-,\.]?([\\(]?([1-9][0-9]{2})[\\)]?))?[,\-,\.]?([^0-1]){1}([0-9]){2}[ ,\-,\.]?([0-9]){4}(()((x){0,1}([0-9]){1,5}){0,1})?$/

1-800-322-5544 or 220-122-2323 (the number used on the form)
Now I'm not a regex guru nor do I work with it every day, so color coding is a definite help for me. There are some nice tools out there that can help you test regex both pay and free. I've been playing with RegExBuilder (free) lately. It doesn't have all the bells and whistles like being able to switch the regex engine, but it works for what I need right now. Anywho, let's break this down:

**- the ? makes the 1 optional

**- this has to be a digit between 1 and 9, never 0

**- two digits that are between 0 and 9

**- any character that is not 0 or 1. Surprisingly, this allows non digits

**- two digits that are between 0 and 9

**- four digits that are between 0 and 9

So according to the test number that was entered in the test, it violates rule **.
The funny thing is that we could have entered anything else besides 0 or 1. I tested 701-B86-5566 and it worked. But anywho… I think this form is performing as expected, unless of course there are valid phone numbers with the ** being 0 or 1. I wouldn’t know where to find that info and a brief google session didn’t turn anything up. I gave up quickly because didn't feel like digging into that right now. I'll leave that up to a more ambitious person. But the question to be answered is whether or not this should be reported as a bug and request Adobe to fix that regex in CF8 to be more accurate on the [^0-1] test. Why not [2-9]?

Blessings...

Token Broken...

This summary is not available. Please click here to view the post.

Wednesday, August 27, 2008

Double execution, my bad

Yesterday was a bug fighting day for me. I might add, twas a frustrating one at that. Here's the scenario:

We have a simple subscribe box allowing users to receive email updates for certain categories if a new job appears in that category. If there is a new user, it should prompt them for their user info. If it is an existing user, it should prompt them for their pin. The problem that I was seeing is that a new user was being prompted for a pin, indicating that this was not a new user at all. The odd part was that it worked in my dev environment but not in our beta or prod environments, same exact code.

So... digging in, I set several cfdumps throughout the application followed by a cfabort.
(Side note: for a cool way to view a stack trace from several levels deep, see Ben Nadel).
I didn't really see anything from that info. All it told me is somehow the record for the user was being created before the code I was observing. That was a head scratcher because I was at the beginning of the code execution. I looked all over the relevant pages for a cflocation or a window.location thinking that somehow it was being recursive. Nothing. I looked at the fusebox parsed file and there was nothing in there that told me it was circling back. Now what? Since this was in beta and we didn't want to turn RDS on, I couldn't do the step through. That wouldn't have helped me anyway knowing now what the issue was. I did turn on debugging and that didn't give me much. I decided to set up a sql trace and found that there was indeed a double execution going on but it simply wasn't showing in my browser.

After lunch I came back and searched on coldfusion and some play on the words "double exexution" and found a blogging from the cf4 days about how some code was causing double execution on an image tag that had a non cfoutputted variable as the src. The explanation came back that the browsesr was seeing the # and going back to the page again for the image causing it to run twice. That got me to thinking. Maybe I should be looking in the iis logs. Sure enough, there it was:

2008-08-26 19:41:27 ******** GET ****** 80 - 69.41.14.80 libcurl-agent/1.0 200 0 0
2008-08-26 19:41:31 ******** GET ****** 80 - ***.***.***.*** Mozilla/5.0+(Windows;+U;+Windows+NT+5.1;+en-US;+rv:1.9.0.1)+Gecko/2008070208+Firefox/3.0.1 200 0 0


One was my browser... but before that was a libcurl-agent. What was that? I was thinking it was some of our data gathering visit trackers but I came up empty googling libcurl in combo with their names. Finally I researched the ip. Using arin.net, I found that this "bot" belonged to

Michigan Online Group MOG-69-41-0-0 (NET-69-41-0-0-1)
69.41.0.0 - 69.41.15.255
Covenant Eyes, Inc. MOG-69-41-14-0 (NET-69-41-14-0-1)
69.41.14.0 - 69.41.14.255


Oh man... Covenant Eyes. That is my integrity software that I am running locally. The filter service gets wind of the site that I want to visit, rushes out and see's it before I do in order to check its content, then flags my system to say that its ok to visit. That was essentially creating the user before my browser could get to it. By the time I got there, it was percieved as a return visit. Man... I just wasted 7 hrs looking into it (I'm obsessive I know). I'm all in favor of running integrity software because we're only as strong as our weakest moments. I still like what Covenant Eyes does, but if you forget about how it works it can cause a few headaches and wasted hours. The fix to this is to set the site url to permanent allow under the Filter History and Settings area. That will stop the filter from "pre-visiting" the sites that you are trying to debug.