Monday 18 May 2015

Lucee CFML: import and application-set mappings (kinda redux)

This is a like a sequel to "Railo bug? Or ColdFusion bug...". That article details how ColdFusion will kind of allow import to use mappings set in Application.cfc, provided an include uses said mapping first. On RailoLucee they stick closer to the docs (that's the ColdFusion docs, not the Lucee docs):

Attribute: taglib
Optionality: required
Description: Tag library URI. The path must be relative to the web root (and start with /), the current page location, or a directory specified in the Administrator ColdFusion mappings page.
My emphasis.

The Lucee docs make no claim about this one way or the other, but that's how Lucee behaves. In short, on Lucee one cannot use Application.cfc mappings with an import statement like that.

One other thing came up though... Sean had made this comment against that blog article:

Since cfimport affects _compilation_ and, in particular, with an empty prefix it means that what look like html tags actually become cf tag invocations, that's why the runtime-supplied application-level mappings are not _supposed_ to impact how cfimport behaves.

And Chris Blackwell cited that understanding today on the Lucee forums:

My understanding ( from Sean Corfield ) is that cfimport is a compile time directive, but application.cfc mappings are runtime. Hence you can not cfimport a tag based on a application.cfc mapping.

Mappings in Web or server admin are known when your template is compiled, so they work ok
Seeing it again I kinda went "yeah, bullshit actually", but decided to test it before firming-up my... opinion.

Here's some code, within a specific directory structure:


// Application.cfc
component {
    // blocking

<!--- tag.cfm --->
This is in <cfoutput>#getCurrentTemplatePath()#</cfoutput><br>

<!--- useAdminMappings.cfm --->
<cfimport taglib="/tags/" prefix="t">

Both tag.cfm files are the same.

First, I go into Lucee Admin and create a mapping, thus:

Virtual: /tags
Resource: D:\path\to\importmappings\tags\a

If I browse to useAdminMappings.cfm, I get this on the screen:

This is in D:\path\to\importmappings\tags\a\tag.cfm

I note the compilation time of all the files concerned.

Now I go back into Admin and change the mapping to point to the b subdirectory and reload. And I see this:

This is in D:\path\to\importmappings\tags\b\tag.cfm

And, looking at the compilation time of all the compiled classes: there's been no change. No surprise there, really.

So the mappings are being processed at run time, just fine.

I had a look at what the CFML compiled (and decompiled) to, and there was nothing in it relating to either the "a" or the "b" directory... it was all just references to "/tags/", and loading the mapping at run time. The full decompilation is here.

On a whim, I tried using a dynamic value in the import call:

<!--- useParam.cfm --->
<cfimport taglib="/tags/#URl.which#" prefix="t">

And that did not work:

So the value in the taglib attribute needs to be there at compile time; but how that value is resolved is done @ run time. This'll be what Sean meant, but I don't think it's really that relevant to the situation.

That being the case... I don't really see any reason why Application.cfc cannot provide the runtime resolution of that mapping.

I tried to update the Lucee docs to make some sort of observation, but didn't quite work out how to do that in the time I had available (I'll write this up later). However I think it'd also be a legit enhancement request to get the behaviour changed here. And there's def an error in the admin, as that suggests mappings made in Application.cfc, but doesn't say anything about "except for taglib resolution. Still: it's not my discussion thread, so I'll leave that to Mike Hnat who was the one that has revisited this (LDEV-355).