March 28, 2014

As you may know the new ColdFusion 10 function SessionRotate works great if you are using ColdFusion sessions (CFID, CFTOKEN), but it doesn't actually rotate the session id or invalidate the underlying J2EE session if you are using JEE sessions. This is documented and by design, because a single J2EE session can span multiple ColdFusion applications on the same domain.

You can still rotate your J2EE sessions, but keep in mind that if you have multiple CF applications on the same domain it will only keep info for the current session (you could probably modify the code to get that working).

<cffunction name="jeeSessionRotate" output="false" returntype="string">
	<cfset var sessionScope = Duplicate(session)>
	<cfset var req = getPageContext().getRequest()>
	<cfset StructDelete(sessionScope, "sessionid")>
	<cfset StructDelete(sessionScope, "urltoken")>
	<!--- invalidate old session --->
	<cfset req.getSession().invalidate()>
	<!--- create a new JEE session --->
	<cfset local.newSession = req.getSession(true)>
	<!--- copy the old session scope into a temp key in the new session, handled in onSessionStart --->
	<cfif NOT StructIsEmpty(sessionScope)>
		<cfset local.newSession.setAttribute("jeeSessionRotateOldSession", sessionScope)>	
	</cfif>
	<cfreturn local.newSession.getId()>
</cffunction>

In your code call the above function to rotate the J2EE session, it will then store the old session scope in the new J2EE session directly with the key jeeSessionRotateOldSession.

Then in the onSessionStart function of your Application.cfc add the following to bring the old session data back into the new CF session:

<cffunction name="onSessionStart">
	<cfset session.startTime = now()>
	<cfset local.oldSession = getPageContext().getRequest().getSession().getAttribute("jeeSessionRotateOldSession")>
	<cfif NOT IsNull(local.oldSession) AND NOT structIsEmpty(local.oldSession)>			
		<cfloop list="#StructKeyList(local.oldSession)#" index="local.key">
			<cfif NOT StructKeyExists(session, local.key)>
				<cfset session[local.key] = local.oldSession[local.key]>
			</cfif>
		</cfloop>	
		<cfset getPageContext().getRequest().getSession().removeAttribute("jeeSessionRotateOldSession")>
	</cfif>
</cffunction>  

This is needed because the CF session scope is no longer usable after you run jeeSessionInvliadate(), so we need to wait until onSessionStart is invoked again with the new jee session to copy the old CF session scope back over.

Note: that the jeeSessionRotate function above only copies values set via CF's session scope, it doesn't copy any values that other JEE applications might have set, it could be modified to do that if you needed to.

March 17, 2014

I was working on a server (CF9.0.2 Win2008 IIS7.5) installation today and ran into what I thought at first was an IIS connector issue. When I setup the server in IIS 6 compatibility mode, it simply returned a blank page, using the IIS 7 connector for ColdFusion 9 was showing me an IIS error page with a 404.0 response from the JWildCardHandler in ExecuteRequestHandler, the file that I was trying to serve was there, IIS had permission to read it. It was not a 404!

I then realized it was not an IIS connector issue (even though it really looked like it to me), but the problem was on the CF side.

In my exception.log I found:

"Error","jrpp-0","03/17/14","15:13:57",,"Could not find the ColdFusion component or interface C:\sites\test\Application.cfc.Ensure that the name is correct and that the component or interface exists. The specific sequence of files included or processed is: C:\sites\test\index.cfm'' "
coldfusion.runtime.CfJspPage$NoSuchTemplateException: Could not find the ColdFusion component or interface C:\sites\test\Application.cfc.
	at coldfusion.runtime.TemplateClassLoader.newInstance(TemplateClassLoader.java:565)
	at coldfusion.runtime.TemplateClassLoader.newInstance(TemplateClassLoader.java:541)
	at coldfusion.runtime.TemplateProxyFactory.getCFCInstance(TemplateProxyFactory.java:271)
	at coldfusion.runtime.TemplateProxyFactory.resolveName(TemplateProxyFactory.java:174)
	at coldfusion.runtime.TemplateProxyFactory.resolveName(TemplateProxyFactory.java:159)
	at coldfusion.runtime.TemplateProxyFactory.resolveFile(TemplateProxyFactory.java:120)
	at coldfusion.cfc.CFCProxy.(CFCProxy.java:92)
	at coldfusion.runtime.AppEventInvoker.(AppEventInvoker.java:48)
	at coldfusion.filter.ApplicationFilter.invoke(ApplicationFilter.java:192)
	at coldfusion.filter.RequestMonitorFilter.invoke(RequestMonitorFilter.java:48)
	at coldfusion.filter.MonitoringFilter.invoke(MonitoringFilter.java:40)
	at coldfusion.filter.PathFilter.invoke(PathFilter.java:94)
	at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:70)
	at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
	at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
	at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
	at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
	at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
	at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
	at coldfusion.CfmServlet.service(CfmServlet.java:201)
	at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
	at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
	at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
	at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
	at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
	at jrun.servlet.FilterChain.service(FilterChain.java:101)
	at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
	at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
	at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
	at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
	at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
	at jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:320)
	at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
	at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:266)
	at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
"Error","jrpp-0","03/17/14","15:13:57",,"File not found: C:\ColdFusion9\wwwroot\WEB-INF\exception\coldfusion\runtime\ApplicationException.cfm The specific sequence of files included or processed is: C:\ColdFusion9\wwwroot\WEB-INF\exception\coldfusion\runtime\ApplicationException.cfm'' "
coldfusion.runtime.TemplateNotFoundException: File not found: C:\ColdFusion9\wwwroot\WEB-INF\exception\coldfusion\runtime\ApplicationException.cfm
	at coldfusion.runtime.TemplateClassLoader.newInstance(TemplateClassLoader.java:567)
	at coldfusion.tagext.lang.IncludeTag.setTemplate(IncludeTag.java:191)
	at coldfusion.tagext.lang.IncludeTag.setTemplatePath(IncludeTag.java:111)
	at coldfusion.filter.CfincludeFilter.invoke(CfincludeFilter.java:64)
	at coldfusion.filter.CfincludeFilter.include(CfincludeFilter.java:33)
	at coldfusion.filter.ExceptionFilter.runBuiltInHandler(ExceptionFilter.java:552)
	at coldfusion.filter.ExceptionFilter.handleException(ExceptionFilter.java:329)
	at coldfusion.filter.ExceptionFilter.invoke(ExceptionFilter.java:84)
	at coldfusion.filter.ClientScopePersistenceFilter.invoke(ClientScopePersistenceFilter.java:28)
	at coldfusion.filter.BrowserFilter.invoke(BrowserFilter.java:38)
	at coldfusion.filter.NoCacheFilter.invoke(NoCacheFilter.java:46)
	at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:38)
	at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
	at coldfusion.filter.CachingFilter.invoke(CachingFilter.java:62)
	at coldfusion.CfmServlet.service(CfmServlet.java:201)
	at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
	at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
	at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
	at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
	at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
	at jrun.servlet.FilterChain.service(FilterChain.java:101)
	at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
	at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
	at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
	at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
	at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
	at jrunx.scheduler.ThreadPool$DownstreamMetrics.invokeRunnable(ThreadPool.java:320)
	at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
	at jrunx.scheduler.ThreadPool$UpstreamMetrics.invokeRunnable(ThreadPool.java:266)
	at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)

The Application.cfc was there and ColdFusion had read permission to it, the ApplicationException.cfm was there and ColdFusion also had read permission to that user.

I was getting this coldfusion.runtime.TemplateNotFoundException but the templates really were there!

So what was the problem?

I had denied write access to C:\ColdFusion9\wwwroot\ for ColdFusion's user account. So what I think happened is that ColdFusion tried to compile the cfm and cfc file (and it needs to write those files into the WEB-INF folder) it didn't have permission to write these files so it threw a TemplateNotFoundException on the file it was trying to compile... even though CF did find it and could read it, it just couldn't save the compiled class.

I had to blog this one because it is such an obscure exception, not sure if too many people will encounter it, but just in case...