Question

I'm working on a JSF 2.2 application where we need to upload some .csv files via the web page. It works fine when we deploy to Tomcat, but for some reason it isn't working with WebSphere. Here is the example below that I am trying to get working:

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

<ui:composition template="/WEB-INF/templates/template.xhtml">
    <ui:define name="header">
        Header
    </ui:define>
    <ui:define name="content">
        <h:messages></h:messages>
        <h:form enctype="multipart/form-data">
            <h:inputFile id="file" value="#{fileUploadManagedBean.file}">
            </h:inputFile>
            <h:commandButton value="Upload"
                action="#{fileUploadManagedBean.upload()}" />
        </h:form>
        <h:outputLabel>JSF Implementation: #{fileUploadManagedBean.jsfImplementation}</h:outputLabel>
        <br />
        <h:outputLabel>JSF Version: #{fileUploadManagedBean.jsfVersion}</h:outputLabel>
    </ui:define>
    <ui:define name="footer">
        Footer
    </ui:define>
</ui:composition>
</html>

And here is my backing bean, FileUploadManagedBean.java

package com.mycomp.test;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.Part;

import org.apache.log4j.Logger;

@ManagedBean
@SessionScoped
public class FileUploadManagedBean {
    public static Logger logger = Logger.getLogger(FileUploadManagedBean.class);
    private Part file;                      // The file being uploaded

    public String upload() {
        logger.info("Initiating bulk upload...");      
        logger.debug("content-type: "+ file.getContentType());
        logger.debug("filename: "+ file.getName());
        logger.debug("size: "+ file.getSize());

        FacesContext facesContext = FacesContext.getCurrentInstance();
        facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Uploaded", "Uploaded"));

        return null;
    }
    public Part getFile() {
        return file;
    }
    public void setFile(Part file) {
        this.file = file;
    }


    public String getJsfImplementation() {
        return  FacesContext.class.getPackage().getImplementationTitle();
    }
    public String getJsfVersion() {
        return  FacesContext.class.getPackage().getImplementationVersion();
    }
}

When I open up the page, it prints out "Mojarra" and "JSF 2.2", so I know that the backing bean is being accessed and that JSF 2.2 is being utilized, but when I click "upload", Java is never called and there are no entries in the WebSphere log; the page just refreshes. When I look at the HTTP packets being sent (from the browser side), I see the file being sent in the POST request, and then I get a 200 OK response.

Any ideas?

Was it helpful?

Solution

After days of debugging and trying alternatives, we discovered that the issue is that WebSphere 8.5.5 requires any servlet trying to read multipart data to either add a multipart-config element to its definition in the web.xml file, or to use the @MultipartConfig annotation. It would appear that the JSF 2.2 servlet was not implementing this correctly, since once we added the multipart-config element to our web.xml file, everything worked fine on WebSphere.

I'm not exactly sure why our code initially worked on Tomcat, but not in Websphere; I suspect that either the JSF 2.2 build we are using is faulty, or Tomcat is just a little more forgiving and didn't require us to be as explicit.

OTHER TIPS

The Primefaces uses two file upload decoder for uploading content of p:fileupload

1- NativeFileUploadDecoder

2- CommonsFileUploadDecoder

NativeFileUploadDecoder is the default upload decoder and it requires servlet container 3.0 so if your servlet container is less than 3 then it will not work with you. also some application servers make a restriction on using multi-part content

so if you have a problem with the native upload decoder for any reason you have to use the other decoder which is "CommonsFileUploadDecoder"

CommonsFileUploadDecoder depends on Apache common lib so you have to put the commons-fileupload and commons-io jars in your class-path the version depends on your primefaces version but 1.3 and 2.2 respectively works for me.

to use CommonsFileUploadDecoder you have to use filter

<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

wait the filter only will not work because inside the filter it checks about the uploader if its not provided and it detect at least JSF 2.2 so it will bypass the request to the default decoder "Native" and then it will not work for your also

to force the filter to use the common decoder you have to put the following context param in your web.xml

<context-param>
<param-name>primefaces.UPLOADER</param-name>
   <param-value>commons</param-value>
</context-param>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top