Got it!

One has been tracing through the Struts 1.1 source to see how it does its
thing and one has worked out why Daniel and oneself are having difficulties.

The problem lies in the way multipart forms are handled differently by the
RequestProcessor.

One of the first calls in RequestProcessor.process() is to
processMultipart(). This will determine whether it is necessary to wrap the
request with a MultipartRequestWrapper. It will NOT however initialise the
parameters of the MultipartRequestWrapper instance yet.

The RequestProcessor will then call other processXXX methods():
processPath, processLocale, processContent, processNoCache,
processPreProcess, processMapping, processActionForm(*).

These calls get passed the request - for a multipartform this is the
MultipartRequestWrapper. This wrapper however has not at this stage had its
parameters initialised - if one overrides these RequestProcessor methods in
ones own RequestProcessor subclass then one cannot make use of
request.getParameter() when one has a multipart request - it will just
return null. For non-multipart requests however, it will work as expected.

After this, processPopulate is called. If form==null (ie: one does not have
any ActionForm associated with this request) then the method will return
immediately , doing nothing.

Otherwise it will delegate to RequestUtils.populate where it checks if a
multipart form is being used.

If this is the case it will get the MultipartRequestHandler (implementing
class instance) and use it to process the request's input stream. THIS is
the point when the parameters in the MultipartRequestWrapper get populated.

After this, the action form is populated from the request using
BeanUtils.populate as per normal.

This logic has certain implications, the most obvious being that if one
submits from a multipart form and one is not using any ActionForm then one
will not have any request parameters, as they will not never be
populated.(**)

We are not amused ;-)

We find this to be a rather odd way of doing things and think it would
surely be much better and more transparent if the parameters in the
MultipartRequestWrapper were initialised immediately in the call to
processMultipart() and thus available to all the other overrideable methods
in RequestProcessor that get called before processPopulate() when using
multipart forms in the same way they already are when using non-multipart
forms.

Such a change should also include making population of parameters in the
MultipartRequestWrapper independent of the ActionForm. That way one would
not be forced to use an ActionForm should one desire to read properties in a
multipart request.

---

(*) This is a darn nuisance for us as we need to get a certain parameter
value in my processActionForm().
(**) My problem was that because my code couldnt read that parameter in
processActionForm(), I couldnt actually get my ActionForm instance, and thus
when I got to my DispatchAction had no parameters to specify which method to
be called...



-----Original Message-----
From: Andrew Hill [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, July 16, 2002 12:53
To: Struts Users Mailing List
Subject: RE: MultipartRequestWrapper.getParameter() not returning
anything


Daniel could have written this a wee bit clearer.
It is indeed the struts request processor and not us that is doing the
wrapping.
The resulting HttpServletRequest (with implementing class of
org.apache.struts.upload.MultipartRequestWrapper) is always returning null
for getParameter() and an empty enumeration for getParameterNames().
(We ARE treating it like any other request - or would be if the code even
got as far as calling our action methods)

This of course kills our dispatch actions <!--Our dispatch action class is
actually a copy&paste job as I wanted to add some convienience methods to
all actions and got sick and tired trying to keep them synced between my
ActionBase and DispatchActionBase. It is just a copy of the dispatch action
in struts but inherits from my GTActionBase class which inherits from
Action, instead of inheriting directly from Action as the original does.-->
as they cannot find their method parameter... (It would also kill a lot of
our own code if execution could even get that far...) Switch the form back
to a normal form (as opposed to a multipart/form-data) enctype, and the
parameters will start working again.

btw: We *have* overridden the RequestProcessor with our own class that
inherits from the struts supplied RequestProcessor, but our class only
overrides the processActionForm() method (and even that delegates to the
super().processActionForm()) when it doesnt have to perform special
handling.
In the process of disagnosing this problem I have overriden
processMultipart() by copying and pasting the method into my request
processor class, and have added two println so I can see it detecting the
multipart nature of the request and choosing to use the wrapper (also moved
the {} to a _readable_ position ;->):

    protected HttpServletRequest processMultipart(HttpServletRequest
request)
    {
      System.out.println("processRequest():Request class=" +
request.getClass().getName()); //<--Added
      if (!"POST".equals(request.getMethod()))
      {
        return (request);
      }
      String contentType = request.getContentType();
      if ((contentType != null) &&
contentType.startsWith("multipart/form-data"))
      {
        System.out.println("Wrapping request with MultipartRequestWrapper");
// <-- Added
        return (new MultipartRequestWrapper(request));
      }
      else
      {
        System.out.println("Request is not for multipart/form-data"); // <--
Added
        return (request);
      }
    }


I added the following method to my DispatchAction superclass (yes - the
copy&pasted clone with funny inheritance):
  private void dumpRequest(HttpServletRequest request)
  {
    System.out.println("Request Class=" + request.getClass().getName());
    System.out.println("Request parameter
dump:-----------------------------");
    Enumeration params = request.getParameterNames();
    while(params.hasMoreElements())
    {
      String param = (String)params.nextElement();
      System.out.println(param + "=" + request.getParameter(param));
    }

System.out.println("----------------------------------------------------");
  }
I call this in the first line of perform() before the code (which is
identical to the _real_ dispatch action as its copied and pasted) excutes.
It is showing the request as having no parameters, a fact backed up by the
dispatch action code which fails as it cant find the method parameter, so
doesnt know which method in the subclass to call...

The full method is below: As you can see, only the dumpRequest() line is
different from the _real_ struts dispatch action. The if(name==null) check
returns true, thus causing the response.sendError() to be called. If the
form is not enctype="multipart/form-data" this check returns false, and the
appropriate method in the subclass will get called...

    /**
     * Process the specified HTTP request, and create the corresponding HTTP
     * response (or forward to another web component that will create it).
     * Return an <code>ActionForward</code> instance describing where and
how
     * control should be forwarded, or <code>null</code> if the response has
     * already been completed.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param actionForm The optional ActionForm bean for this request (if
any)
     * @param request The HTTP request we are processing
     * @param response The HTTP response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    public ActionForward perform(ActionMapping mapping,
                 ActionForm form,
                 HttpServletRequest request,
                 HttpServletResponse response)
    throws IOException, ServletException {
dumpRequest(request);
        // Identify the request parameter containing the method name
        String parameter = mapping.getParameter();
        if (parameter == null) {
            String message =
                messages.getMessage("dispatch.handler", mapping.getPath());
            log.error(message);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               message);
            return (null);
        }

        // Identify the method name to be dispatched to
        String name = request.getParameter(parameter);
        if (name == null) {
            String message =
                messages.getMessage("dispatch.parameter", mapping.getPath(),
                                    parameter);
            log.error(message);
            response.sendError(HttpServletResponse.SC_BAD_REQUEST,
                               message);
            return (null);
        }

        // Invoke the named method, and return the result
        return dispatchMethod(mapping,form,request,response,name);

    }

-----Original Message-----
From: Martin Cooper [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, July 16, 2002 12:11
To: 'Struts Users Mailing List'
Subject: RE: MultipartRequestWrapper.getParameter() not returning
anything


You shouldn't be doing any wrapping yourself - the use of the wrapper is
internal to Struts, and should be transparent to you. If you remove any of
your own code that's trying to use the wrapper (i.e. just assume it's a
normal request), things should start working.

--
Martin Cooper


> -----Original Message-----
> From: Daniel J. D'Cotta [mailto:[EMAIL PROTECTED]]
> Sent: Monday, July 15, 2002 8:58 PM
> To: Struts Users List
> Subject: MultipartRequestWrapper.getParameter() not returning anything
>
>
> Hi,
>
> I am using Struts 1.1-B1 with Tomcat 4.0.3.
>
> When I change my form enctype to 'multipart/form-data' and
> wrap the request
> into a MultipartRequestWrapper, the getParameter() and
> getParameterNames()
> are not returning any values at all.
>
> Has anyone encountered this problem before. Is there any work around?
>
>
> Regards,
> Daniel D'Cotta
>
> Ext: 212
>
>
> --
> To unsubscribe, e-mail:
<mailto:[EMAIL PROTECTED]>
For additional commands, e-mail:
<mailto:[EMAIL PROTECTED]>



--
To unsubscribe, e-mail:
<mailto:[EMAIL PROTECTED]>
For additional commands, e-mail:
<mailto:[EMAIL PROTECTED]>


--
To unsubscribe, e-mail:
<mailto:[EMAIL PROTECTED]>
For additional commands, e-mail:
<mailto:[EMAIL PROTECTED]>


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to