Undefined error when using CFThread in Custom Tags in ColdFusion 10 - coldfusion

NOTE: I have completely rewritten this question to take into account new information. Please reread if you've already been through this one.
I'm getting errors when using a cfthread from within a custom tag in ColdFusion 10. In the Application log, I get the following entries:
Variable _cffunccfthread_cfThreadTag2ecfm16902001291 is undefined.
The name of the function it's returning as an error is _cffunccfthread_cf[Page Name Calling the CFThreadTag] then a number that doesn't change from request to request. I can duplicate this every time with the following code:
Application.cfc:
component
{
this.name = "CFThreadCustomTagTest";
}
ThePage.cfm:
<cfthread action="run" name="ThreadTestInPage">
<cflog log="Application" text="The thread in the page successfully ran" type="information" />
</cfthread>
<cf_ThreadTag />
ThreadTag.cfm:
<cfif thisTag.ExecutionMode EQ "start">
<cfthread action="run" name="ThreadTest">
<cflog log="Application" text="The thread within the tag successfully ran" type="information" />
</cfthread>
</cfif>
Just drop all three files in a directory in ColdFusion 10 and load ThePage.cfm. I get the following entries in the Application log:
"Severity","ThreadID","Date","Time","Application","Message"
"Information","ajp-bio-8012-exec-1","06/19/12","07:18:11",,"C:\ColdFusion10\cfusion\logs\application.log initialized"
"Information","cfthread-11","06/19/12","07:18:15","CFTHREADCUSTOMTAGTEST","The thread in the page successfully ran"
"Error","cfthread-9","06/19/12","07:18:15",,"THREADTEST: Variable _cffunccfthread_cfThreadTag2ecfm16902001291 is undefined. "
I also noticed that in the error for the thread within the custom tag, it does not contain the application name. While the log entry for the thread in the page does. Notice that the error line simply has ,, for the Application column of the log, while the successful thread has "CFTHREADCUSTOMTAGTEST".
If I change ThreadTag.cfm to wait for the thread within the tag to finish processing, then everything works fine, and I get the two entries in the log as I expect:
<cfif thisTag.ExecutionMode EQ "start">
<cfthread action="run" name="ThreadTest">
<cflog log="Application" text="The thread within the tag successfully ran" type="information" />
</cfthread>
<cfthread action="join" name="ThreadTest" timeout="10" />
<cfdump var="#cfthread#">
</cfif>
And to verify that there are no funky settings anywhere, here's my local development environment's settings summary.
So it seems that if I just throw the thread out there, and don't wait for it to finish, then the thread seems to be looking for something from the parent page that is no longer in memory. At least that's my completely unfounded guess :).
I've also filed a bug with Adobe. Bug number 3218452.

I understand your predicament, but there's no actual question here.
Basically you've found a bug in CF. A few people - myself included - can replicate it.
No-one's missing anything, except for the Adobe engineers who missed including this sort of thing in their regression testing when implementing CF10. That's no indictment of them, really, as I think this is reasonably edge case, perhaps?
The "variable" CF ain't finding is actually the name of the compiled class that the CF compiler makes when compiling the code. It looks like there's a compiler bug to me.
For example, my error is this:
THREADTEST: Variable _cffunccfthread_cfThreadTag2ecfm13713410591 is undefined.
However the compiled class is:
cfThreadTag2ecfm1371341059$func_CFFUNCCFTHREAD_CFTHREADTAG2ECFM13713410591.class
I don't know what part of the class name the variable is supposed to be named for, but I suspect it should be looking for func_CFFUNCCFTHREAD_CFTHREADTAG2ECFM13713410591. Or on the other hand the compiler should not be compiling the ThreadTag.cfm file as a FUNCTION? But I'm guessing... it might need to compile the thread code as a function so as to call it in a separate thread? That's a guess. Either way: it's compiling the code as one thing, and then looking for a different thing. because of a bug.
But bottom line here: yep, you've found a bug. And you've flagged it with Adobe. I dunno what else there is for you to do here?
So basically we now know one cannot have a <cfthread> call in a custom tag (I also tested via <cfmodule>: same problem). You're gonna have to write yer code a different way, using an include or a method or something. Less than ideal, I know, but what can you do?
Footnote:
I looked at the compiled code and it looks like the problem is CF is compiling the class with that func_ prefix, but it's referring to it in its code without. I didn't follow the code all the way to checking everything that's happening, but it looks to me like there are references to it trying to load _cffunccfthread_cfThreadTag2ecfm13713410591 rather than the correct name: func_CFFUNCCFTHREAD_CFTHREADTAG2ECFM13713410591.class.

Dan,
Please look on this page:
http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec0b2e1-7ff0.html
And this section "Determining the tag execution mode"
And try the equivalent mode check code <cfswitch expression=#thisTag.ExecutionMode#>
To see if this causes a different compiler code gen. Maybe it will gen code a bit different and the variable will get generated.
Also, another test to try is to put you tag first in "ThePage.cfm" and see if that causes a different code gen as well.
Finally, are you on a newer JVM, as newer ones use the latest Fork/Join features of the Java concurrency approach such as Futures, etc. and they may be causing different code gen. Maybe set your JDK to an older one and see if the code gen is different.
No real answer, but some things to look at.

I ran into this as well.
My solution was to refactor and put the cfthread stuff into a .cfc and call that from the .cfm page.

Related

Cannot find qryname14411 key in structure

I have an error that seems to be associated with <cfscript> db operation
// traffic tracking
myQry = new Query();
myQry.setSQL("INSERT INTO dbo.Traffic (Circuit, Fuseaction, IP_hash) VALUES (:circuit, :fuseaction, :ip_hash)");
myQry.addParam(name="circuit", value="#listfirst(rc.fuseaction, '.')#", cfsqltype="CF_SQL_VARCHAR");
myQry.addParam(name="fuseaction", value="#listlast(rc.fuseaction, '.')#", cfsqltype="CF_SQL_VARCHAR");
myQry.addParam(name="ip_hash", value="#cgi.remote_addr#", cfsqltype="CF_SQL_VARCHAR");
myQry.execute();
The really strange thing is, it looks like the operation completed. What kind of a error is this?
Short answer: It's probably a scoping issue. Try:
var myQry = new Query();
Long-winded waffley answer:
I'd call it an Adobe-developers-being-useless kind of error.
If you look at line 460 of that file, you'll see the error is due to a failure of StructFind to find the query name in the variables scope, and the reason it's appearing in debug input is because there's a try/catch with type any surrounding it. The same functionality could be achieved without causing/catching an error by replacing the try/catch with <cfif StructKeyExists(variables,tagAttributes['name']) > which is basic CFML knowledge, and certainly something a developer of the CF product should know!
The same code still exists in the CF10 version of base.cfc, so you may or not feel like submitting it as a bug in Adobe's CF bugbase - though it's unlikely they'll fix it for CF9 (and uncertain whether they'll feel CF10 is worth the effort either).
However, that would only be side-stepping the issue of the variable not existing, not addressing the real issue of why it doesn't actually exist. Given that the debug info shows the query is successfully executing, and the query code is basically right above that line (starts at line 442), it shouldn't be a repeated/common error, but it may be due to your myQry variable not being scoped, and thus it could be colliding with another variable also called myQry (or even the same var from a separate call to the function) which is happening between the execution of the new Query() and .execute() lines, and thus causing the original query to not be there when the StructFind looks for it.
The solution is to put the keyword var before the first use of myQry which will place it in the local scope for that function - something that should be done for all variables that are only for use within an instance of a function, (otherwise they are placed in the variables scope of the component/request that the function exists within).

Coldfusion and SVNKit Log

I am trying to use SVNKit to get a Log of the SVN Entries in Coldfusion. I downloaded the latest SVNKit jar files and threw them in the lib folder under WEB-INF/lib.
Here is my code that should return an Array Of Log Entries but this code is returning a Null Pointer exception in Coldfusion 9.0.2.
SVNURL = createObject('java','org.tmatesoft.svn.core.SVNURL').parseURIEncoded(svnurl);
drf = createObject("java","org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory");
drf.setup();
rf = drf.create(SVNURL);
SVNWCUtil = createObject("java","org.tmatesoft.svn.core.wc.SVNWCUtil");
authManager = SVNWCUtil.createDefaultAuthenticationManager(user,pass);
rf.setAuthenticationManager(authManager);
log = rf.log(JavaCast("String[]",[]),JavaCast("null",""),JavaCast("long",10),JavaCast("long",15),true,true);
rf.closeSession();
When running this code, I receive the following Error.
The system has attempted to use an undefined value, which usually indicates a programming error, either in your code or some system code.
Null Pointers are another name for undefined values.
Which points to this line..
log = rf.log(JavaCast("String[]",[]),JavaCast("null",""),JavaCast("long",10),JavaCast("long",15),true,true);
I moved this same code over to Railo, and everything is running fine. I just cannot see why ACF is choking on the log() method.
I was using the Printing Out Repository History example on the SVNKit Wiki to start me off.
Any suggestions on getting it to work in Adobe Coldfusion would be greatly appreciated. I did not test on CF10.
I wasn't using the JavaCast("boolean",true) for the last two arguments in the log() function. After that, everything worked fine.
Got to remember to check and use JavaCast()!
log = rf.log(JavaCast("String[]",[]),JavaCast("null",""),JavaCast("long",10),JavaCast("long",15),JavaCast("boolean",true),JavaCast("boolean",true));

Any way to block out new code for legacy versions of CF

I have written a library I include for some security patches. In that library there are a number of CF8 and up function,attributes,etc.
I really really dont want to cut the functionality down bc adobe couldnt get it together and get this basic functionality into CF7 so Im looking to write separate lines into each function. The issue is when CF is initially reading the code it bugs out if it finds something it doesnt recognize, whether or not it is going to be called.
For example in cfdirectory CF7 doesnt support the 'type' attribute. I have a find directory function that fails in CF7 when the 'type' attribute is present and taking it out increases the search time by 10x.
<cftry>
<cfdirectory action="list" directory="#arguments.start#" name="LOCAL.dirquery" type="dir" /><!---//GET QUERY OF DIRECTORIES IN START DIRECTORY--->
<cfcatch>
<cfsetting requesttimeout="600">
<cfdirectory action="list" directory="#arguments.start#" name="LOCAL.dirquery" /><!---//GET QUERY OF DIRECTORIES IN START DIRECTORY--->
</cfcatch>
This code does not work, neither does a conditional block. Im guessing the reader cannot parse thsi into whatever language and so is failing.
The code is probably failing at compile time, not at run time (need to see the error you are receiving to know for sure). If it's a compiler error, you'll need to have break out your CF7 functions in separate components from your CF8+ functions. Then check the CF version at run time to determine which component/function to call.
Here's some pseudo code you can use in application startup to load the correct version functions into memory. That way you have a consistent interface for calling the functions anywhere in your code.
Pseudo Code:
onApplicationStart(){
if (server.coldfusion.productversion == 7){
application.cffunctions = CF7FunctionsComponent;
} else {
application.cffunctions = CF8FunctionsComponent;
}
}
Everywhere else, you call the same function regardless of CF version currently running:
application.cffunctions.doSomething();

ColdFusion Application.cfc & cfinvoke & THIS scope

In using the CF application.cfc - there is a need to create some vars to begin with (in the THIS scope) - such as this.name and this.applicationtimeout() etc.
I ran across something I consider an odd behavior - and hope someone can explain why this happens and a possible workaround.
There are quite a few "THIS" vars accepted that can work to set application specific variables (of course you have to check "allow application specific vars" in the CFADMIN - which I did)
One of these is THIS.mappings - which is an array of mappings - MINE looks something like this:
this.path = GetDirectoryFromPath( GetCurrentTemplatePath() );
this.mappings = {
'/files' = '#this.path#_my_files\'
,'/functions' = '#this.path#_my_functions\'
,'/logs' = '#this.path#_my_logs\'
};
it works fine - when it is set inside a cfscript block at the top of the application.cfc
it works fine - if I put that script block in it's own file and cfinclude it in the application.cfc
however - In an attempt to segment my code - I wanted to put ALL of my application setting in a settings.cfc... (the thought here was IF some setting had to be changed - I wouldn't have to worry about 'where' to look, I don't really want to split the THIS stuff on my app.cfc and other application or session settings in the settings.cfc
SO I created a method in the settings.cfc called getTHIS, and I put the script block there... then used
<cfinvoke component="settings"
method="getTHIS"
returnvariable="THIS"
/>
Which WORKS - except (it seems) on the mappings...
The this.name etc, all seem to work and get set - as a matter of fact the this.mappings gets set fine too (so it appears) if i do a
<cfdump var="#THIS#" label="THIS" />
The dump is identical to the dump of THIS when I set it 'literally' on the app.cfc page..
HOWEVER - any attempt to call a template thru the mapping - results in a standard "if you want to use absolute paths you have to create a mapping blah blah..."
MY BIGGER goal was (on application start) to scan a directory for sub-directories, and create mappings based on certain sub-directories.. but if I can't abstract that functionality out into it's own function - I'll be forced to write it directly in the app.cfc (which wouldn't KILL me, but again, I was trying to segment my code logically... There seems to be a limitation of when and where these mappings can be set... true?
So I guess the big question is - can I SET this.mappings thru an outside method??
I guess I could bring back the 'settings I want' using the cfc call, and then just do the 'set this.whatever = return form cfc' - (this may be my answer...)
Thanks
Mappings can only be set in the 'pseudo-constructor' and not inside any of the methods inside Application.cfc - http://adobe.ly/QN2oX1
You could try setting this.mappings to the result of a CFC call (I cannot think of why this would not work), but if it depends on a mapping to do so, it will likely not work.
I haven't tested this, but I'm pretty sure it would work if your application.cfc extends your settings.cfc.
component {
public any function getMappings() {
var mappings = {};
//code to get your directories etc.
return mappings;
}
}
component extends="settings" {
this.name = "xxxx";
this.mappings = getMappings();
...
}

Coldfusion 8 - mapping conflict causes "argument is not of interface type" error

I have been researching this, and cannot seem to find anything about it.
We work on CF8. When my coworker tried installing my latest code updates, he started seeing errors that the argument supplied to a function was not of the specified interface type. Worked fine for me. Same set up. Sometimes it works for him. Also have the problem on our dev server.
I have since been able to isolate and reproduce the problem locally.
Here is the set up.
I have 2 mappings on the server:
"webapp/" goes to c:\webroot\
"packages/" goes to c:\webroot\[domain]
Then I created an interface, call it ISubject and a component that implements it, called Person, and saved both under packages. Here is the declaration for Person:
cfcomponent implements="packages.ISubject"
Finally, there is a component, called SubjectMediator with a function, called setSubject, that wants an object of the ISubject interface type. Here is the argument declaration for setSubject:
cfargument name="subject_object" type="packages.ISubject"
To implement:
variables.person = createObject("component", "packages.Person").Init();
variables.subjectMediator = createObject("component", "packages.SubjectMediator ").Init();
variables.subjectMediator.setSubject(variables.person);
That last line throws the error that Person is not of type ISubject. If I do isInstanceOf() on Person against ISubject it validates fine.
So the reason this is happening? Dumping getMetaData(variables.person) shows me that the interface path is webapp.[domain].ISubject. And indeed, if I change the type attribute of the argument to use this path instead of packages.ISubject, all is fine again.
Coldfusion seems to be arbitrarily choosing which mapping to resolve the interface to, and then simply doing a string comparison for check the type argument?
Anyone had to contend with this? I need the webapp mapping, and I cannot change all references to "packages" to "webapp.[domain]." I also am not able in this instance to use an application-specific mapping for webapp. While any of these 3 options would circumvent the issue, I'm hoping someone has some insight...
The best I've got is to set argument type to "any" and then check isInstanceOf() inside the function... Seems like poor form.
Thanks,
Jen
Can you move the contents of the packages mapping to outside the webroot? This seems like the easiest way to fix it.