views:

157

answers:

4

Hi all

I need to use onApplicationEnd() as part of Application.cfc to execute a call on a 3rd party Java object to close a connection to another device on the network.

The code I have worked perfectly if I call it as a normal request, but when I place it in the onApplicationEnd() method I'm running into some errors. These errors suggest that CF might in fact be shutting down already to the point where I cannot access these 3rd party Java classes.

Code:

    <cffunction name="onApplicationEnd" returnType="void">
 <cfargument name="appScope" required="true" />

 <cfset var logLocation = "test" />

 <cflog file="#logLocation#" text="*** [Application.cfc]  - **** START RUN ****" />
 <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() called " />


 <cftry>

  <cfif structKeyExists(ARGUMENTS, "appScope")>
   <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - ARGUMENTS.appScope is defined" />
  <cfelse>
   <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - ARGUMENTS.appScope is undefined! " />
  </cfif>

  <!--- Check if we have a test crypto object in scope, and if so close it's connection --->
  <cfif structKeyExists(ARGUMENTS.appScope, "testCrypto")>

   <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() - crypto object exists in app scope" />

   <cfset ARGUMENTS.appScope.testCrypto.closeConnection() />
   <<cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() - closed crypto server connection" />

  <cfelse>
   <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() - NO crypto server connection present to close" />
  </cfif>

   <cfcatch type="any">

    <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() - Error - #cfcatch.message#" />

   </cfcatch>

  </cftry>
 <cflog file="#logLocation#" text="*** [Application.cfc]  - #timeformat(now(),'HH:mm:ss' )# - onApplicationEnd() ended " />

</cffunction>

The line to close the connection on my object is failing with the message: 'java.lang.IllegalStateException: Shutdown in progress'.

Here are the full logs for one run:

"Information","Thread-8","10/23/09","09:05:54",,"*** [Application.cfc]  - **** START RUN 

"Information","Thread-8","10/23/09","09:05:54",,"*** [Application.cfc]  - 09:05:54 - onApplicationEnd() called "

"Information","Thread-8","10/23/09","09:05:54",,"*** [Application.cfc]  - 09:05:54 - ARGUMENTS.appScope is defined"

"Information","Thread-8","10/23/09","09:05:54",,"*** [Application.cfc]  - 09:05:54 - onApplicationEnd() - crypto object exists in app scope"

"Information","Thread-8","10/23/09","09:05:54",,"*** [Application.cfc]  - 09:05:54 - onApplicationEnd() - Error - Shutdown in progress"

"Information","Thread-8","10/23/09","09:05:55",,"*** [Application.cfc]  - 09:05:55 - onApplicationEnd() ended "

Is there restrictions to what I can do in onApplicationEnd() and if so is there any work around?

I am using CF 8 (8,0,1,195765) Developer Edition on a Windows XP machine.

Also, if I run CF in a console window and press CTRL-C I see this, but I also see this behaviour if I run cfstop.

Many thanks in advance!

EDIT: Some others had this issues here, but no solutions.

EDIT: Removed thread example as it might be fogging the issue. Posted code and logs.

A: 

Have you tried restarting?

WahWah
+2  A: 

according to the docs "You cannot use this method to display data on a user page, because it is not associated with a request."

I think the "is not associated with a request." is the key. It could be that your java objects only exist within the request thread and not in the app instance.

Perhaps instead you shound try using onRequestEnd

http://livedocs.adobe.com/coldfusion/8/AppEvents%5F09.html

ryber
Hm. It sounded to me like the object was only created in OnApplicationEnd, and perhaps it was trying to access some data that is not available to it from within OnApplicationEnd. Though it is really hard to say without seeing the error message ..or some code.
Leigh
The java object I am trying to access lives in the Application scope. That scope is passed to the onApplicationEnd() method AFAIK. The error message for the thread test is brutal, just the thread name and a null pointer exception. Would use request end but this really needs to be the last thing done before server stops. Will post some code soon.
Ciaran Archer
Yes, a copy of the application scope is passed into OnApplicationEnd. I would skip the tests with the "parallel thread" for now. Just focus on errors that occurs when using the application scoped object directly.
Leigh
@ciaranarcher .. Hm, just to clarify, do you really mean before the _server_ stops?
Leigh
@ciaranarcher can you post the code? I also noticed that you must access the Application variables through the Arguments scope. So Arguments.ApplicationScope.myVariable, not Application.myVariable. Not sure if that could be part of the problem
ryber
Thanks for the replies - code and logs posted.
Ciaran Archer
@Leigh - just to clarify - we do not usually stop an application running unless we are doing a restart of CF. So I need any applications caught up in this server restart to gracefully close any connections they have to the 3rd party device. I presumed that onApplicationEnd() would be called and allowed to finish before the server got to the point in it's shutdown where it cannot execute certain things. It looks like I am wrong on this I guess.
Ciaran Archer
+3  A: 

It sounds like this may be caused by the fact that the server is shutting down, rather than just the CF application. I am guessing that if the JVM is already in the process of shutting down, the resources your java class uses might not be available at that point. So onApplicationEnd might not be the correct place for that code.

You might want to look into adding a ShutdownHook. I am not 100% positive, but I think placing the cleanup code there, instead of in onApplicationEnd might allow the java object to do its cleanup before the JVM enters its death throes stage.

But having said all that, would not the "connection to another device on the network" be closed automatically once the server shuts down?

Leigh
I agree that this might be the case and will investigate using this hook. I am using CF 8, I think 9 has this built into Application.cfc. Regarding your last comment: the whole reason I have to do this is the lack of a graceful shutdown of the connection to the third party device.
Ciaran Archer
Ciaran Archer
After a lot of testing and some more discussion here : http://forums.adobe.com/message/2337930#2337930 I cannot find a way that this can be done reliably. Even creating a thread and passing it to the server runtime shut-down hook is no good, I get a null pointer exception despite the thread running fine outside of a server shut-down contexts. Many thanks for the help everyone, I'm implementing a work-around to call the shut-down code explicitly before application end, i.e. via a normal request.
Ciaran Archer
@ciaranarcher, Sorry I got a bit busy myself. I know you said you implemented a work-around, but if you would not mind, could you post the code you tried? I would be interested to see the attempted implementation. – Leigh
Leigh
+1  A: 

Well my first thought is that the server doesn't actually stop when the application stops... The application will stop, but the server is liable to keep chugging along. If you have a directory with an older Application.cfm in it and just some flat .cfm files in that directory, people can request those cf pages and they can be not associated with any kind of application context. So you can actually have no applications running and still be serving lots of CF pages. Granted, that's not how people generally set up their CF servers, but they do work that way. There's been some talk of creating a Server.cfc like Application.cfc in a future version, although I don't know if they've implemented it in CF9.

My second thought is that the only way for the onApplicatinEnd method to cause the specific error "java.lang.IllegalStateException: Shutdown in progress" would be if the java objects you're referencing are java objects that are somehow intrinsically linked to the application context, such as objects that you might access through the undocumented ColdFusion.server.ServiceFactory. But the code you've posted doesn't look like that's happening.

It's a long shot, but you could try placing the testCrypto object in a local / temp variable within the onApplicationEnd method and executing it from there.

Sorry I couldn't be more helfpul.

Isaac Dealey