Upload seam mail page and send it
kasper110382 Mar 29, 2010 10:29 PMHi everyone,
I'm trying to upgrade my Seam application from JBoss AS 4.x to 5.x and Seam Mail is giving me a headache because I'm seeing different behaviour on the different app. servers. I think this is possibly a bug and I think I have the solution. Let me first tell you about the app:
- It's packaged as an .ear with two .war files in it.
- The app is designed to allow upload of .xhtml files to be rendered as Seam Mail pages.
- The way we do this is something like this (simplified):
@In Renderer renderer; public void sendMail(byte[] uploadedBytes, String filename) { ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext(); File uploadDir = new File(servletContext.getRealPath("/uploads")); File uploadedFile = new File(uploadDir, filename); // write uploadedBytes to 'uploadedFile' renderer.render("/uploads/" + filename); }
This works fine in JBoss 4.x but it doesn't in JBoss 5.x or 6.x. It throws an exception because the resource (
"/uploads/" + filename
) cannot be found.
I've done some debugging and found a couple of hints as to what goes wrong:
- The faceletForViewId(...) method in RendererRequest uses ResourceLoader to resolve the resource.
- The ResourceLoader uses ServletLifecycle.getCurrentServletContext() to resolve the resource.
- The ServletContext returned ServletLifecycle.getCurrentServletContext() is not the same servlet context as FacesContext.getCurrentInstance().getExternalContext().getContext(). I think this is perhaps because the code above is placed in a Stateless EJB so a ServletContext for the whole .ear is returned by ServletLifecycle? Anyways - looking into catalina's source code there are some if's based on
isFileSystemBased()
which return true on JBoss 4 and false on JBoss 5/6 - depending on this you get null or areal
url when calling getResource(...). - I created this replacement ResourceLoader which seems to work, but it's a messy solution. I think maybe this code should be pushed down to Seam's source:
@Scope(ScopeType.STATELESS) @Name("org.jboss.seam.core.resourceLoader") @Install(precedence=Install.APPLICATION) public class MyResourceLoader extends ResourceLoader { @Override public URL getResource(String resource) { URL result = super.getResource(resource); if (result == null) { ServletContext servletContext = (ServletContext) FacesContext .getCurrentInstance().getExternalContext().getContext(); try { result = servletContext.getResource(resource); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } } return result; } }
Also - this propagates to other parts of Seam Mail, such as UIAttachment, where the encodeEnd(...) method uses the FacesResources class (which is not a Seam component, so I cannot hack it by replacing it with my own alternative). In other words: Although I managed to hack ResourceLoader, I cannot support uploaded attachments in JBoss 5/6 as I could in JBoss 4! :-(
Help would be VERY MUCH appreciated as I have tried fixing this issue for several weeks now.