How to inherit from another Application.cfc - coldfusion

I have a test application structured like so:
Application.cfc
ApplicationProxy.cfc
index.cfm
sub_app/
Application.cfc
index.cfm
and I want my sub app to inherit all variables and events from the top level Application.cfc.
I have read and implemented Sean Corfield's ApplicationProxy method for extending an Application component but I can't get it to work as when I visit sub_app/index.cfm I get this error:
Could not find the ColdFusion Component or Interface ApplicationProxy.
From the error I can only guess that the application is looking in the wrong place, how do I correct this?
Application.cfc:
<cfcomponent name="Application" output="true">
<cfset THIS.name = "testAppA">
<cfset THIS.sessionManagement="Yes">
<cfset THIS.applicationTimeout = createTimeSpan(0,0,10,0)>
<cfset THIS.sessionTimeout = createtimespan(0,0,10,0)>
<cfset THIS.clientManagement = true>
<cfset THIS.clientStorage = "cookie">
<cfset THIS.loginStorage = "cookie">
<cfset THIS.setDomainCookies = false>
<cfset THIS.setClientCookies = true>
<cfset THIS.scriptProtect = true>
<cfset THIS.secureJSON = true>
<cffunction name="onApplicationStart" returntype="void">
<cfset APPLICATION.name = "testAppA">
<cfset APPLICATION.test = "test var">
</cffunction>
<cffunction name="onSessionStart" returntype="void">
<cfset SESSION.loggedIn = 1>
</cffunction>
</cfcomponent>
ApplicationProxy:
<cfcomponent name="ApplicationProxy" extends="Application">
</cfcomponent>
index.cfm:
Sub app
sub_app/Application.cfc:
<cfcomponent extends="ApplicationProxy" output="true">
<!---
Uses parent Application settings
--->
</cfcomponent>
sub_app/index.cfm:
Parent app
<cfdump var="#Application#">

Best way to do is create ApplicationProxy.cfc file with all function you need to inherit and then extends in Application.cfc wherever needed. I am using this method since long time and no issue face with this approach.

Related

Application scoped variables are getting refreshed for each requests

We've migrated a ColdFusion application from ColdFusion 10 to ColdFusion 2016. After Migration, Application variables are not staying in its scope, it is refreshing on each and every request.
Consider the following example,
Application.cfm
<cfsetting enablecfoutputonly="true" />
<CFAPPLICATION NAME="Test App"
SETCLIENTCOOKIES="YES"
CLIENTMANAGEMENT="YES"
SESSIONMANAGEMENT="YES"
SESSIONTIMEOUT="#CREATETIMESPAN(0,8,0,0)#"
APPLICATIONTIMEOUT="#CREATETIMESPAN(1,0,0,0)#">
<cfdump var="#Application#" label="app">
<CFLOCK SCOPE="APPLICATION" TYPE="EXCLUSIVE" TIMEOUT="10">
<CFSET Application.Email = "test#test.com">
<CFSET Application.DataSource="test">
</cflock>
Test.cfm
<CFLOCK SCOPE="APPLICATION" TYPE="READONLY" TIMEOUT="10">
<cfset Application.one = 1>
<cfset Application.two = 2>
<cfset Application.three = 3>
</cflock>
OnRequestEnd.cfm
<cfsetting showdebugoutput="false" />
<cfdump var="#Application#" label="onRequestEnd">
So if we request /test.cfm
it'll throw the following output
Again refreshing the page also giving the same output
Not sure why the Application scoped variables are losing its persistence.
the following is the expected output..
Any idea of Why the application variables are lost and getting refreshed on each and every request ?
I haven't tested this code, but what you're seeing is the procedural order of operation performed by Application.cfm. You're essentially redefining the application on every request, which is why on the name exists in your initial dump and the rest exist on the dump in onRequestEnd.
If you update your code to use Application.cfc, you can ditch the cflock code, better organize your "triggers" and define your application variables once, when needed, using onApplicationStart.
<cfcomponent>
<cfset this.name = "Test App">
<cfset this.SETCLIENTCOOKIES="YES">
<cfset this.CLIENTMANAGEMENT="YES">
<cfset this.SESSIONMANAGEMENT="YES">
<cfset this.SESSIONTIMEOUT="#CREATETIMESPAN(0,8,0,0)#">
<cfset this.APPLICATIONTIMEOUT="#CREATETIMESPAN(1,0,0,0)#">
<cfsetting enablecfoutputonly="true" />
<cffunction name="onApplicationStart" access="public" returnType="void" output="false">
<cfset application.Email = "test#test.com">
<cfset application.DataSource="test">
</cffunction>
<cffunction name="onRequestStart" access="public" returntype="boolean" output="false">
<cfset application.one = 1>
<cfset application.two = 2>
<cfset application.three = 3>
<cfreturn true>
</cffunction>
<cffunction name="onRequestEnd" access="public" returntype="boolean" output="false">
<cfsetting showdebugoutput="false" />
<cfdump var="#application#" label="onRequestEnd">
<cfreturn true>
</cffunction>
</cfcomponent>
This should define email and datasource in the application scope one time, when the app first loads. The variables one, two and three will be created at the start of each request, but you can add a check to set them only if they don't already exist.
You can then use child Application.cfc files to help modularize your application using sub-folders and sub-application specific variables. They'll still exist in the scope of the larger application, but you'll be able to manage them from a location specific to a sub-app this way.

Invalid Component Definition

I'm having an issue in the logs I cannot replicate on the browser. I'm getting hundreds of these per day
invalid component definition, can't find component [cfc.udf]
The cfc are stored in a cfc folder one level above the app. This is so that many apps can use the same cfc.
Folder structure:
---- cfc
--------- udf.cfc
---- myApp
--------- application.cfc
In the application.cfc, I'm using application-specific mappings because this is set on a lot of different load-balanced-servers in production as well as a QA environment and local testing environment and keeping them all synced would be difficult.
At onRequestStart, I have a function that restarts the application every 5 minutes. It was supplied by a consultant. I suspect that this is the culprit because the logs show these errors coming in at exactly 5 minute intervals
<cfcomponent>
<cfset This.name = "myApp">
<cfset This.Sessionmanagement=true>
<cfset This.Sessiontimeout="#createtimespan(0,0,30,0)#">
<cfset this.mappings['/cfc'] = ExpandPath('../cfc')>
<cffunction name="onApplicationStart">
<cfset Application.udf = createObject("component", "cfc.udf").init()>
</cffunction>
<cffunction name="onRequestStart">
<cfset appRefreshMinutes = 5>
<cfif Not IsDefined("Application.refreshTime")>
<cfset currentMinute = Minute(Now())>
<cfset Application.refreshTime = DateAdd("n", -(currentMinute MOD appRefreshMinutes)+appRefreshMinutes, Now())>
<cfset Application.refreshTime = DateAdd("s", -(Second(Application.refreshTime)), Application.refreshTime)>
</cfif>
<cfif Now() GTE Application.refreshTime Or IsDefined("URL.reload")>
<cflock name="ApplicationInit" type="exclusive" timeout="5" throwontimeout="false">
<cfif Now() GTE Application.refreshTime Or IsDefined("URL.reload")>
<cfset OnApplicationStart()>
<cfset Application.refreshTime = DateAdd("n", appRefreshMinutes, Application.refreshTime)>
</cfif>
</cflock>
</cfif>
</cffunction>
</cfcomponent>
Promoted from the comments
Have you tried using a mapping name other than /cfc? Like:
<cfset this.mappings['/somethingelse'] = ExpandPath('../cfc')>
so that you can then call it like:
<cfset Application.udf = createObject("component", "somethingelse.udf").init()>
Maybe it just looks odd to me or maybe that is causing your issue (cfc being a reserved word or somehow getting special treatment in this case).

ColdFusion session variables are not accessible in other pages

My dept. has just bought CF10 and I'm finally updating my existing web app to CF10 from CF8.
My first problem with CF10 is using session variables. When using the lower versions of CF (CF4 to CF8) I have never had any problem setting up session variables and getting or using these variables in other pages after a successful login. With CF 10 it seems setting session variables and using them in other pages are major problems. I'm not sure what have I done wrong in the code.
First I'm setting the session in my Application.cfc this way:
<cfcomponent displayname="Application" output="true">
<cfset THIS.Name ="MyNewApp"/>
<cfset THIS.ApplicationTimeout = CreateTimeSpan(0,0,20,0) />
<cfset THIS.SessionManagement ="YES"/>
<cfset THIS.SessionTimeout = CreateTimeSpan( 0, 0, 20, 0 ) />
<cfset THIS.SetClientCookies = false />
<cffunction name="OnApplicationStart" access="public" returntype="boolean"
output="false">
<cfset application.Main_DSN = "TESTDB">
<cfreturn true />
</cffunction>
<cffunction name="onApplicationEnd" output="false">
<cfargument name="applicationScope" required="true">
</cffunction>
<cffunction name="OnSessionStart" access="public" returntype="void" output="false"
hint="Fires when user session initializes.">
<cfset session.loggedin = "NO">
<cfset session.username = "">
<cfset session.userrights = "">
<cfset session.usergroup = "">
</cffunction>
</cfcomponent>
After login, user is validated and set values to those session.variables:
........user validation codes here......................
<cfif mylogin NEQ true>
<cflocation url="/login/login.cfm">
<cfabort
<cfelse>
<cfset session.loggedin="Yes">
<cfset session.username="#Trim(Form.username)#">
<CFSET qUserRights = LoginObj.getUserRights('#Trim(Form.username)#')>
<cfset session.userrights = qUserRights><!--- it's a query --->
<CFSET qUserGroup = LoginObj.getUserGroup('#Trim(Form.username)#')>
<cfloop query="qUserGroup">
<cfset session.usergroup = user_group>
<cfbreak>
</cfloop>
<!--- ******* ?????????????????????????
When I do cfdump in at this level, I can see that all of these session variables have
been assigned to their values.
But these session variables are not accessible from other pages. Other pages still show
these session variable without its value.
So, when I use these cfdumps in the index.cfm it is shown as they're not yet assigned
with any values ********* --->
<cfdump var="#session.loggedin#">
<cfdump var="#session.username#">
<cfdump var="#session.userright#">
<cfdump var="#session.usergroup#">
</cfif>
In index.cfm, Before Login I got:
session.loggedin = NO
session.username = ["empty string"]
session.userrights = ["empty string"]
session.usergroup = ["empty string"]
After a successful Login:
session.loggedin = NO
session.username = ["empty string"]
session.userrights = ["empty string"]
session.usergroup = ["empty string"]
Have I done something wrong? This code works on CF8.
I need to mention: CF10 is in Linux and my web app is under https not http. But these session variables should be shared between http and https because some older pages are still in http and can not be moved to https.
I do not have a direct answer to this question. However, the problem is not only in CF10. I am experiencing this in CF8. I create session variables in my application.cfc however they cannot be seen (accessed) in other pages. I believe in your case you may want to consider case sensitive checks since you are on a Linux platform as rudimentary as this may seem if all else fails.

Application.CFC variable not available

In application.cfc I am defining a variable which must be available throughout a session.
<cfcomponent>
<cfset this.applicationTimeout = createTimeSpan(0,4,0,0)>
<cfset this.sessionManagement = true>
<cfset this.setClientCookies = true>
<cfset this.sessionTimeout = createTimeSpan(0,0,90,0)>
<cfset this.setdomaincookies = true>
<cfset this.myVar = "Hello">
</cfcomponent>
I tried several approaches to get the myVar in .cfm but to no avail.
Approach 1: <cfoutput>#myVar#</cfoutput>
Approach 2: <cfoutput>#session.myVar#</cfoutput>
Approach 3: <cfoutput>#application.myVar#</cfoutput>
Any help would be appreciated.
You're confusing the placement of Application.cfc's this-scoped settings with your own application-scoped variables.
Take a look at Ben Nadel's Application.cfc tutorial.
You basically want to put application.myVar in OnApplicationStart():
<cfcomponent>
<cfset this.applicationTimeout = createTimeSpan(0,4,0,0)>
<cfset this.sessionManagement = true>
<cfset this.setClientCookies = true>
<cfset this.sessionTimeout = createTimeSpan(0,0,90,0)>
<cfset this.setdomaincookies = true>
<cffunction name="OnApplicationStart">
<cfset application.myVar = "Hello">
</cffunction>
</cfcomponent>
Then you should be able to reference it in your application as application.myVar.

Railo to talk to XMPP/Jabber/Google Talk from within Railo?

I have implemented ColdFusion XMPP Event Gateway in coldfusion server 10 and it is working fine with google talk. The same thing i want to implement in Railo server but no luck to find something.
Please suggest something to "Railo to talk to XMPP/Jabber/Google Talk from within Railo"
Used cfc file in coldfusion XMPP event gateway
<cfcomponent displayname="EventGateway" hint="Process events from the test gateway and return echo">
<cffunction name="onIncomingMessage" output="no">
<cfargument name="CFEvent" type="struct" required="yes">
<cflog file="#CFEvent.GatewayID#Status" text=" onIncomingMessage; SENDER: #CFEvent.Data.SENDER# MESSAGE:
#CFEvent.Data.MESSAGE# TIMESTAMP: #CFEvent.Data.TIMESTAMP# ">
<!--- Get the message --->
<cfset data=cfevent.DATA>
<cfset message="#data.message#">
<!--- where did it come from? --->
<cfset orig="#CFEvent.originatorID#">
<cfset retValue = structNew()>
<cfif listcontains("XMPP ", arguments.CFEVENT.GatewayType) gt 0>
<cfset retValue.BuddyID = orig>
<cfset retValue.MESSAGE = "echo: " & message>
<cfelseif arguments.CFEVENT.GatewayType is "Socket">
<cfset retValue.originatorID = orig>
<cfset retValue.message = "echo: " & message>
<cfelseif arguments.cfevent.gatewaytype is "SMS">
<cfset retValue.command = "submit">
<cfset retValue.sourceAddress = arguments.CFEVENT.GatewayID>
<cfset retValue.destAddress = orig>
<cfset retValue.shortMessage = "echo: " & message>
</cfif>
<!--- we can write our script to process like database Query here --->
<!--- send the return message back --->
<cfreturn retValue>
</cffunction>
<cffunction name="onAddBuddyRequest">
<cfargument name="CFEvent" type="struct" required="YES">
<cflock scope="APPLICATION" timeout="10" type="EXCLUSIVE">
<cfscript>
// If the name is in the DB once, accept; if it is missing, decline.
// If it is in the DB multiple times, take no action.
action="accept";
reason="Valid ID";
//Add the buddy to the buddy status structure only if accepted.
if (NOT StructKeyExists(Application,"buddyStatus")) {
Application.buddyStatus=StructNew();
}
if (NOT StructKeyExists(Application.buddyStatus,CFEvent.Data.SENDER)) {
Application.buddyStatus[#CFEvent.Data.SENDER#]=StructNew();
}
Application.buddyStatus[#CFEvent.Data.SENDER#].status="Accepted Buddy Request";
Application.buddyStatus[#CFEvent.Data.SENDER#].timeStamp=
CFEvent.Data.TIMESTAMP;
Application.buddyStatus[#CFEvent.Data.SENDER#].message=CFEvent.Data.MESSAGE;
</cfscript>
</cflock>
<!--- Log the request and decision information. --->
<cflog file="#CFEvent.GatewayID#Status" text="onAddBuddyRequest; SENDER: #CFEvent.Data.SENDER# MESSAGE:
#CFEvent.Data.MESSAGE# TIMESTAMP: #CFEvent.Data.TIMESTAMP# ACTION: #action#">
<!--- Return the action decision. --->
<cfset retValue = structNew()>
<cfset retValue.command = action>
<cfset retValue.BuddyID = CFEvent.DATA.SENDER>
<cfset retValue.Reason = reason>
<cfreturn retValue>
</cffunction>
<cffunction name="onAddBuddyResponse">
</cffunction>
<cffunction name="onBuddyStatus">
</cffunction>
<cffunction name="onIMServerMessage">
</cffunction>
</cfcomponent>
Thanks,
Arun