views:

679

answers:

1

15:11:14,676 WARN FacesRequestAttributes:121 - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@1059fd6] for attribute 'purchaseController' because FacesRequestAttributes does not support such callbacks

This warn message appears in my log a lot. For every managed bean whenever it expires. It expires after a given time, because I'm using MyFaces Orchestra.

I have defined the org.springframework.web.context.request.RequestContextListener in my web.xml, and I don't have the spring jar only ones on my classpath (i.e. not a class-loading problem)

The docs of FacesRequestAttribute says:

NOTE: In contrast to ServletRequestAttributes, this variant does not support destruction callbacks for scoped attributes, neither for the request scope nor for the session scope. If you rely on such implicit destruction callbacks, consider defining a Spring RequestContextListener in your web.xml.

The purchaseController is actually a simple managed bean (not extending anything an implementing only Serializable), annotated with @Controller.

Update1:

The beans in @Scope("request") and @Scope("session") seem to be affected. So I wanted to know whether this warn poses any danger to the proper flow. I.e. if something really needs those callbacks. If not, I will just skip the warning with the lo4j config.

Update 2:

I digged a little further, and it seems that this happens only sometimes. IF the listener is used, then RequestContextHolder.currentRequestAttributes() returns the ServletRequestAttributes, rather than FacesRequestAttributes. So it appears that sometimes the listener doesn't work and doesn't set the current attributes in the RequestContextHolder.

Update 3:

I turned debug on for RequestContextListener, and here's the result:

07:21:31,518 DEBUG RequestContextListener:69 - Bound request context to thread: org.apache.catalina.connector.RequestFacade@1190ae9
07:21:31,518 DEBUG RequestContextListener:89 - Cleared thread-bound request context: org.apache.catalina.connector.RequestFacade@1190ae9
07:21:31,538  WARN FacesRequestAttributes:121 - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@11aa152] for attribute 'org.apache.myfaces.orchestra.conversation.AccessScopeManager' because FacesRequestAttributes does not support such callbacks
07:21:31,541  WARN FacesRequestAttributes:121 - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@1552393] for attribute 'localeController' because FacesRequestAttributes does not support such callbacks
....and so on, other request and session beans

It appears that the request gets destroyed before access to the beans is attempted. Which is very odd. Could this be due to a problem in the servlet container implementation of the listener handling?

+2  A: 

In the javadoc of FacesRequestAttributes, we can read:

Note: In contrast to ServletRequestAttributes, this variant does not support destruction callbacks for scoped attributes, neither for the request scope nor for the session scope. If you rely on such implicit destruction callbacks, consider defining a Spring RequestContextListener in your web.xml.

And, indeed, the registerDestructionCallback() method of FacesRequestAttributes doesn't do much things:

public void registerDestructionCallback(String name, Runnable callback, int scope) {
    if (logger.isWarnEnabled()) {
        logger.warn("Could not register destruction callback [" + callback + "] for attribute '" + name +
                        "' because FacesRequestAttributes does not support such callbacks");
    }
}

But my understanding is that the RequestContextListener (that you have declared) will take care of this job. Its requestDestroyed(ServletRequestEvent requestEvent) method is shown below:

public void requestDestroyed(ServletRequestEvent requestEvent) {
   ServletRequestAttributes attributes =
           (ServletRequestAttributes) requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
   ServletRequestAttributes threadAttributes =
           (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
   if (threadAttributes != null) {
       // We're assumably within the original request thread...
       if (attributes == null) {
           attributes = threadAttributes;
       }
       RequestContextHolder.resetRequestAttributes();
       LocaleContextHolder.resetLocaleContext();
   }
   if (attributes != null) {
       attributes.requestCompleted();
       if (logger.isDebugEnabled()) {
           logger.debug("Cleared thread-bound request context: " + requestEvent.getServletRequest());
       }
   }
}

And if you look at the javadoc of ServletRequestAttributes#requestCompleted():

Executes all request destruction callbacks and updates the session attributes that have been accessed during request processing.

So, I think that you can safely skip the WARN with log4j configuration (maybe confirm this with a little debugging session though).

Pascal Thivent
Thanks, +1 for the time spent.I digged a little further, and it seems that this happens only _sometimes_. As you (and me) quoted, FacesRequestAttributes don't have callbacks. But IF the listener is used, then RequestContextHolder.currentRequestAttributes(); returns the ServletRequestAttributes, rather than FacesRequestAttributes. So it appears that sometimes the listener doesn't work..
Bozho
Weird, the method you mention should *Fall back to the current JSF FacesContext, if any*. But I'm kinda talking out of my ass and feel too lazy tonight to go further :)
Pascal Thivent
yes, it does fall back to the FacesContext via constructing a new FacesContextAttributes(FacesContext.getCurrentInstance()), and that's the problem - this object doesn't register callbacks. What can be the reason for it to fall back to it instead of using the one registered by the listener.
Bozho