3 Replies Latest reply on Oct 4, 2011 4:48 PM by monrealis

    FileUpload in Richfaces 4.0.0.Final and MyFaces 2.0.5.SNAPSHOT

    jgoodfellow

      I have file upload working with Richfaces 4.0.0.Final and MyFaces 2.0.5-SNAPSHOT.
      I had to use a couple of hacks to get it to work which hopefully won't be necessary in the future. The first problem is probably a MyFaces bug.  Nick opened a bug with MyFaces (https://issues.apache.org/jira/browse/MYFACES-3043) which they have marked fixed but there are still javascript errors when you have a response with no request.
      I include a javascript file after the MyFaces & Richfaces javascript includes with this statement:
      var passThruResponse = jsf.ajax.response;
      jsf.ajax.response = function(request, context) {
          if (context._mfInternal == undefined) {
           context._mfInternal = { _mfSourceControlId : null,
                                   _mfSourceFormId : "uploadForm" };
          }
          passThruResponse(request, context);
      };

      The second hack is required to fix a problem which may be in Richfaces or Myfaces.  Basically the problem is that the multipart request processing happens in a method called FacesContext.getPartialViewContext().  Richfaces creates a new request object and replaces the current request in the external context to handle the multipart request.  The problem is that FacesContext.getPartialViewContext() isn't called until the Apply Request Values phase.  During the first phase, Restore View, a method is called to see whether or not to skip all the phases and go directly to the render phase.  This method is ResponseStateManager.isPostback(FacesContext).  Now isPostback looks for the request parameter "javax.faces.ViewState" which will not be found until after the multipart request is parsed.  So what happens is that Apply Request Values phase is skipped.  My code below is a hack to detect the fileupload request using the query string.  I don't know if there's anything Richfaces could do to solve this problem or if MyFaces will have to provide some way to get around it.  I'd appreciate if someone could take a look.

      in faces-config.xml:
      <faces-config>
          <factory>
             <render-kit-factory>com.mycompany.myfaces.MyFacesRenderKitFactoryImpl</render-kit-factory>
          </factory>
      </faces-config>

      in MyFacesRenderKitFactoryImpl.java:
      package com.mycompany.myfaces;

      import javax.faces.context.FacesContext;
      import javax.faces.render.RenderKit;
      import javax.faces.render.RenderKitWrapper;
      import javax.faces.render.ResponseStateManager;
      import javax.servlet.http.HttpServletRequest;

      import org.apache.myfaces.renderkit.RenderKitFactoryImpl;
      import org.apache.myfaces.renderkit.html.HtmlResponseStateManager;

      public class MyFacesRenderKitFactoryImpl extends RenderKitFactoryImpl
      {
          private static final String UID_KEY = "rf_fu_uid=";

          @Override
          public void addRenderKit( String renderKitId, RenderKit renderKit )
          {
              super.addRenderKit( renderKitId, new MyFacesRenderKitWrapper( renderKit ) );
          }

          private static class MyFacesRenderKitWrapper extends RenderKitWrapper
          {
              private final RenderKit renderKit;
              private final ResponseStateManager responseStateManager;
             
              public MyFacesRenderKitWrapper( RenderKit renderKit )
              {
                  this.renderKit = renderKit;
                  this.responseStateManager = new MyFacesHtmlResponseStateManager();
              }
             
              @Override
              public RenderKit getWrapped()
              {
                  return renderKit;
              }

              @Override
              public ResponseStateManager getResponseStateManager()
              {
                  return responseStateManager;
              }
          }
         
          private static class MyFacesHtmlResponseStateManager extends HtmlResponseStateManager
          {
              @Override
              public boolean isPostback( FacesContext context )
              {
                  return super.isPostback( context ) || isUploadRequest( context );
              }
             
              private boolean isUploadRequest( FacesContext context )
              {
                  HttpServletRequest request = ( HttpServletRequest ) context.getExternalContext().getRequest();
                  String queryString = request.getQueryString();
                  if ( queryString != null && queryString.contains( UID_KEY ) )
                  {
                      context.getPartialViewContext();   // force parsing of stream to get javax.faces.ViewState
                      return true;
                  }
                  return false;
              }           
          }
      }