Problem with Seam Mail and FacesContext
tagrossr Sep 11, 2009 8:48 PMHi there,
I'm working with Seam 2.2.1-SNAPSHOT. The goal is to send a message to multiple recipients with seam mail. When I send one email it will work most of the time (after 3 up to five mails it will fail although). But when I'm working through a list of recipients it will fail on the second rendering. I always get a:
19:20:59,437 ERROR [STDERR] java.lang.IllegalStateException |@LOCATION: org.jboss.logging.util.LoggerStream.write(LoggerStream.java:152) 19:20:59,453 ERROR [STDERR] at com.sun.faces.context.FacesContextImpl.assertNotReleased(FacesContextImpl.java:395) |@LOCATION: org.jboss.logging.util.LoggerStream.write(LoggerStream.java:152) 19:20:59,484 ERROR [STDERR] at com.sun.faces.context.FacesContextImpl.getExternalContext(FacesContextImpl.java:147) |@LOCATION: org.jboss.logging.util.LoggerStream.write(LoggerStream.java:152) 19:20:59,484 ERROR [STDERR] at com.sun.faces.util.RequestStateManager.getStateMap(RequestStateManager.java:276) |@LOCATION: org.jboss.logging.util.LoggerStream.write(LoggerStream.java:152) ...
I hope someone know this problem or have a clue how to fix.
I have a Gateway which will invoke the send method of the EmailOutAdapter. The EmailOutAdapter will invoke the render method of the FaceletsRenderer.
My classes
@Name(MessageGateway.COMPONENT_NAME) @Scope(ScopeType.APPLICATION) public class MessageGateway { ... @Asynchronous public void sendMessage(List<Transmission> transmissions) { for (Transmission transmission : transmissions) { EmailOutAdapter eoa = (EmailOutAdapter) Component.getInstance(EmailOutAdapter.class); eoa.send(transmission); } } ... }
@Name(EmailOutAdapter.COMPONENT_NAME) @Scope(ScopeType.EVENT) public class EmailOutAdapter implements Adapter { ... public void send(Transmission transmission) { Contexts.getEventContext().set("transmissionToSend", transmission); try { Renderer renderer = (Renderer) Component.getInstance(Renderer.class); renderer.render(TEMPLATE); } catch (IllegalStateException ise) { ise.printStackTrace(); } ... }
I debugged it and found out that the problem is in the RenderRequest.class. In the first round there is no FacesContext available so it will create one and all is fine (1). In the second the FacesContext.getCurrentInstance() will not return null and there's the problem. It gets this FacesContext but the state of the Context is released = true (2) and will end up in the IllegalStateException when it tries to get the Application (3).
package org.jboss.seam.ui.facelet; ... public class RendererRequest{ ... private void init() { request = new MockHttpServletRequest(HttpSessionManager.instance()); response = new MockHttpServletResponse(); setContextClassLoader(); // If a FacesContext isn't available, set one up if (FacesContext.getCurrentInstance() == null) { // (1) good case facesContext = RendererFacesContextFactory.instance().getFacesContext(request, response); } else { // (2) bad case facesContext = FacesContext.getCurrentInstance(); } // Generate the FacesContext from the JSF FacesContextFactory originalFacesContext = FacesContext.getCurrentInstance(); DelegatingFacesContext.setCurrentInstance(facesContext); // Create the viewRoot // (3) ends up in a mess when it tries to get the application because the context state is released UIViewRoot newRoot = facesContext.getApplication().getViewHandler().createView(facesContext, viewId); facesContext.setViewRoot(newRoot); // Set the responseWriter to write to a buffer writer = new StringWriter(); facesContext.setResponseWriter(facesContext.getRenderKit().createResponseWriter(writer, null, null)); } } ... }
Do I've lost sight of something? I'm thankful for every clue.
kind regards
Thomas