5 Replies Latest reply on Apr 5, 2010 10:46 PM by Kasper Sørensen

    Upload seam mail page and send it

    Kasper Sørensen Newbie

      Hi 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 a real 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.