CFML, Clojure, Software Design, Frameworks and more...

Extending Your Root Application.cfc

April 12, 2005 ·

As some people have discovered, you cannot easily extend the Application.cfc in your webroot because of the way CFMX searches for CFCs (extends="Application" in your subdirectory's Application.cfc fails because it looks in that directory first before searching the webroot).
You can get around this by creating a 'proxy' CFC in your webroot:
Here's your root CFC /Application.cfc:

With application sharing we'll one Application.cfc per application and each one will use the same application name (won't extend the upper level Application.cfc). However it seems that this might cause to produce buggy applications since CF wires up event-handlers for first request. I'm afraid similar issues might occur with inheritance since if sub Application.cfc executed first, the upper level application will use the event-handlers of the sub one.

Initially, I used ApplicationProxy to extend the root level App.cfc from subfolders. When we got a mapping to wwwroot, I took out ApplicationProxy and used the mapping to point to the correct Application.cfc in the extends attribute. However, this works just fine without an ApplicationProxy.cfc in wwwroot when I try to hit a page in root/admin/subfolder (each child extending its parent Application.cfc) but it does not work when I try to hit a page in root/dev/subfolder. Any ideas on the inconsistency in functionality?

One component can be said to extend another. However, we cannot say the same of two applications.

Though Application.cfc is a component, it conceptually represents an application. I therefore think it is conceptually bad design for one Application.cfc to extend another, as one application cannot be said to extend another.

You may well be faced with the choice of extending the Application.cfc. It is a sign that you have to initiate a new application, with its own Application.cfc.

@BKBK, well, in ColdFusion, the concept of &quot;application&quot; is extremely loose at best and it is perhaps more reasonable to think of submodules of a single application where the submodules need additional initialization or per-request behavior.

For example, you create an application and use onRequest() and then you want to expose web services. You create a new &quot;application&quot; that extends your base application and then in onRequestStart() you run super.onRequestStart() and then structDelete(this,&quot;onRequest&quot;); structDelete(variables,&quot;onRequest&quot;); to ensure those methods don't intercept your web service calls.

In Fusebox 5.5, the core files provide a template Application.cfc that you are expected to extend in all of your applications. It provides basic infrastructure to initialize the Fusebox and process each request. In your extended application, you set the application name and add any custom initialization you need. It's a very clean idiom.

I think your problem is you're focusing too much on what a traditional application really is...

The concept of &quot;application&quot; is not as loose as you suggest. In any case, not in the present context.

I don't know why you say I'm focussing on what a traditional application is. On the contrary, my eyes are very much on the ball. The theme itself, Application.cfc, narrows the concept down to the Application framework of Coldfusion MX. There then emerges a well-defined, quite specific concept of application. This livedocs page says something about it:

Some of the examples you give are actually workarounds for Coldfusion's shortcomings. That the OnRequest event breaks webservices is one such issue. I believe the Coldfusion Team would admit it is a shortcoming, and might even be working on a soluton as we speak. In any case, what is the point of extending a component -- Application.cfc or Dog.cfc -- only to surgically remove parts -- variables.onRequest or variables.fetch -- afterwards?

The concept of application is extremely loose. Any program can, at any time during its execution, change which &quot;application&quot; it is associated with merely by using the cfapplication tag- and can even use name=&quot;&quot; to gain access to *all* &quot;applications&quot; running on the server.

The point here is that an &quot;application&quot; in ColdFusion (and JSP) is merely a name that certain variables are associated with. Every page could be a different &quot;application&quot; or every application on your server could be part of the same &quot;application&quot;.

As for removing parts of an object - you need to think in terms of a dynamic language and not try to compare this with Java or C# or whatever, where classes are sealed and cannot be modified at runtime.

As per Ben Dolman, cfcomponent extends=&quot;/.Application&quot; works. Case in point, setup /root/Application.cfc as you normally would without Sean's ApplicationProxy. Setup another /root/subdir/Application.cfc with the above cfcomponent declaration which works. I've only tested this 1 directory-level deep. I'm not positive about how this path translates to the namespace notation that coldfusion uses, doesn't really make sense.

The one thing you absolutely need to make sure of is that there is not a CF Mapping of &quot;/&quot; to a different directory than /root. Either remove the &quot;/&quot; mapping or make sure &quot;/&quot; maps to your root. Someone

@Jim &amp; @Ben, interesting to hear that works. I've no idea why since it's not a valid path. I would say that's undocumented, unsupported behavior and not something you should rely on - I can imagine it breaking in a future version of CF...

@Sean, the ApplicationProxy.cfc works great! I tried the other solutions from the comments but could not get the extends=&quot;/.Application&quot; or /root/Application to work. Not sure how they did it, but i think i'll stick with the proxy example for my stuff.

I was curious about the structDelete(...,...) examples you provided in the comment, should i delete all methods that i'm not using from the parent? or is that mainly when dealing with webservices? I wasn't clear if they should only be deleted during webservice calls.

@Possum, creating a mapping for &quot;/&quot; can cause all sorts of problems and is not recommended. ColdFusion knows how to locate the webroot.

I was chatting with a consultant recently who had spent hours debugging problems on a server - only to realize the client had made a mapping to &quot;/&quot;. As soon as that was removed, everything worked.

I have not been aware of Sean's last post about the &quot;non-standard&quot; attributes that one passes to cfcomponent, until now. In answer, yes, I know that the data you pass to a component may form part of the component's metadata. Why ask?

To provide a little more information, my Login page is part of the root, front-end app, but after login, I cannot pass the session info from the (root) application.CFC to the admin application.CFC without extending the (root). I am considering going with one of the many frameworks out there and/or removing the admin application.CFC all together. Locally, I do not have a mapping to &quot;/&quot;, so I think I am spinning my wheels at a problem that may be a simple syntax or CF8 configuration issue. I appreciate you guys spending some time with me.

In unrelated news, what ever happened to the COAL project. I was a contributor there and then it completely fell of the radar. Which framework took its place?

Okay, it appears the &quot;slash-dot&quot; notation mentioned above (/.Application) works at the host (CrystalTech), but does not work in my local environment. That tells me that the &quot;slash-dot&quot; method is either undocumented and/or unreliable. The ApplicationProxy method, on the other hand has not worked in either. Please advise.

(I'm using CF8 developer eddition and my local development site is located @ c:\ColdFusion8\wwwroot\MySite. I am using the standalone CF Server so the path is http://localhost:8501/MySite)

Possum Jones, you said:&gt; I am attempting to extend my root &gt; Application.CFC into an (root)/admin/Application.CFC.

Then you added later:&gt; ... my local development site is located&gt; @ c:\ColdFusion8\wwwroot\MySite. I am using the &gt; standalone CF Server so the path &gt; is http://localhost:8501/MySite

There seems to be a contradiction there. In the first statement, the admin directory comes after the root. Whereas, in the second statement, it is the MySite directory that comes after the root. You should clear that up before we can proceed.

Though Coldfusion doesn't complain about &lt;cfcomponent name=&quot;Application&quot;&gt;it is wrong to use the name attribute in the cfcomponent tag. Name is not an attribute of the cfcomponent tag, so leave it out.

@BKBK, it is not *wrong* to use those attributes. cfcomponent allows any attributes. It adds them to the metadata. That is the point of using &quot;non-standard&quot; attributes. There are frameworks out there that rely on that sort of thing.

SeanThere is a problem whenever I submit a comment. Even though my comment appears here, I get two e-mails telling me my message hasn't been delivered.

One is from &quot;noreply at interajans dot com&quot; and has subject line, &quot;Message Delivery Failure&quot;. The other is from my provider's Mail Delivery System and has subject line, &quot;Undelivered Mail Returned to Sender&quot;. It tells me my message to &quot;kcorrea at indiana dot edu&quot; could not be delivered, and returns a copy of my message.

@BKBK, you clearly are not very well-informed about the Internet. Those bounce-back messages are just telling you that two people who commented on this thread used incorrect email addresses. The message you quote is pretty clear about that!

@BKBK, the whole point of metadata is to add annotations - additional attributes. The built-in attributes cannot be sufficient by definition. You clearly are not very well-informed about metadata either.

Sean, you say, &quot;@BKBK, the whole point of metadata is to add annotations - additional attributes. The built-in attributes cannot be sufficient by definition. You clearly are not very well-informed about metadata either.&quot;

You asked me whether I know that the &quot;non-standard&quot; attributes of cfcomponent eventually form part of the tag's metadata. I said yes. I am therefore just as astonished as before why the pressing need to go into instruction mode.

You have presumed too much. I know what metadata is. Told you so. I also told you I wasn't a fan of metadata. At least, not the way it's applied in Coldfusion. The expected reaction would have been for you to ask me why not. In any case here are some reasons

1) The built-in attributes are sufficient. By that I mean, user-defined attributes are not required to complement the built-in attributes. For example, returning to the original code in this thread, cfcomponent already has built-in attributes to represent the component name. There is therefore no need for a user-defined name-attribute.

2) Information-hiding is not possible with Coldfusion's metadata.

3) cfcomponent is a template for objects in Coldfusion. However, user-defined attributes contribute nothing to state or behaviour, and so add an extra layer of complexity without the functionality. That reduces cohesion. Achieving higher cohesion is higher in my design priorities than either of the two main uses of metadata, namely, extra documentation and attribute-value retrieval.

4) One usually needs an object instantiation to get metadata. That is expensive and, in my opinion, unnecessary. In fact, give me any use case in Coldfusion that involves metadata, and I'll give you an alternative, more cohesive object-oriented design that doesn't involve it.

@BKBK, user-defined attributes are allowed so that frameworks can take advantage of the additional metadata. They are *optional* - just because *you* don't like them doesn't mean others should not use them.

As for your assertion that &quot;One usually needs an object instantiation to get metadata.&quot;, that is incorrect. getComponentMetadata() will return the metadata without instantiating a component.

Sean, you say, &quot;@BKBK, user-defined attributes are allowed so that frameworks can take advantage of the additional metadata. They are *optional* - just because *you* don't like them doesn't mean others should not use them.&quot;

Fair enough. It's all down to choices. The abstraction, generality, customization and aspect-orientation of a framework versus the clutter in the interface of your components, lack of information hiding, and so on. That said, Coldfusion's implementation of metadata is too ad hoc and not as well thought out as, for example, Java's annotations. But it will develop in the near future, I am sure. For the time being, any Coldfusion framework that makes use of user-defined attributes in cfcomponent can be refactored so as to avoid the additional metadata.

You also say, &quot;As for your assertion that 'One usually needs an object instantiation to get metadata.', that is incorrect.&quot;

What I say is correct. The usual way to obtain metadata is to call the method getMetadata(), which requires an object as parameter. The key word is usual. GetMetadata() has been there since MX, but the function you mention, getComponentMetadata(), has only just come in with Coldfusion 8.

@BKBK, just remember that ColdFusion is not Java. ColdFusion is a dynamic scripting language that runs on a JVM. ColdFusion has far more in common with (J)Ruby and Groovy and so on. Thinking in Java will not produce efficient, idiomatic ColdFusion code...

@Sean Corfield, I'm not suggesting that one should apply the same development paradigm for Coldfusion and Java. As you rightly say, it wont produce efficient, idiomatic ColdFusion code.

What I'm against is the chuck-it-all-in culture that we have in Coldfusion development. Some parts of the language's design even encourage this implicitly. I see user-defined metadata in cfcomponent as one such example.

Advocating lean, cohesive code and solid software structure is not the same as thinking in Java. Those are key considerations in the development of Coldfusion, Ruby and Groovy, too, or of any other language for that matter.

Excess of any kind makes code more difficult to maintain. It is well known that 50-75% of the costs that software incurs during its lifetime goes to maintenance.

@Sean Corfield, you say, &quot;@BKBK, you clearly are not very well-informed about the Internet. Those bounce-back messages are just telling you that two people who commented on this thread used incorrect email addresses. The message you quote is pretty clear about that!&quot;

The subject may be off-thread, but it has an impact on the thread. The messages are distracting. I have received 20 since yesterday. It is your blog. I gave you the information in the hope that you will do something about it.

You apparently misunderstood me. I didn't ask what the messages were. I know what they are. In fact, you can easily trace the identity of the owner of one the e-mail addresses on the web. And, yes, the person once responded to this thread. More relevant, however, is the message that said my comments to the blog have not been delivered. Am I ill-informed to wonder if the e-mail could have come from you, the owner of the blog? There's the beauty of the internet -- no one can presume to know it all.

I'm having trouble with extending the onSessionStart() of my root Application.cfc. The onApplicationStart() is extending so it must be in my sub/App.cfc's onSessionStart().Here's what I have:root/Application.cfcroot/ApplicationProxy.cfcroot/admin/Application.cfc

What I get is &quot;loginFailed is undefined in session&quot; when I run my page. This is supposed to be set in the root/app.cfc. The onApplicationStart() variable is getting set from the root/app.cfc, as well as the onSessionStart() variable, UserDept, from the root/admin/app.cfc. It's just not looking at the root/app.cfc to get the other session variables.

I'm extending an Application.cfc for the first time and I, too, am encountering a problem. However, I do not think it is related to the technique as I think I've got it coded correctly. But I am getting an error in the OnRequestStart method that a session variable is not defined when it is clearly defined in OnSessionStart methods of both the parent and child CFCs. I have debugging turned on and can see that no other session variables have been defined yet either, all I see are the standard ColdFusion variables: cfid, cftoken, sessionid, urltoken, and cftoken.

I'll post some code if need be, but I'm initially just curious to understand if there is something that is fundamentally wrong here.

The error is pointing to a session variable I call from an include that is in onRequestStart. I've reviewed the execution scheme of the Application.cfc methods so I do not know why the session scope is not registering before request scope.