tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Tomás Kelly <kel...@taylodge.com>
Subject Custom HttpServletRequestWrapper and then jsp:param
Date Tue, 26 Oct 2010 11:48:16 GMT
Hi folks,

All that follows is being developed/tested in Tomcat 5.5.29

I'm scratching my head a little here.  I wrote a custom http servlet
request wrapper (code below) to allow me to manipulate some of the
parameters for a given request.  I was forced down this path to
continue using some third party software to which I don't have access
to source code nor have permission to change.  I tried the filter and
yay! - in my test case it worked fine.  The parameters I wanted to
manipulate were being changed as I expected.

So I plumbed it into my application and immediately hit a roadblock.
Parameters set using the jsp:param tag in jsp's were not being set
(null values when read using .getParameter() in the included page).
I've debugged and can see my wrappers 'getParameter()' method being
called at the appropriate point - but of course the map I'm reading
has no knowledge of parameters set using the jsp:param tag.  To my
knowledge the container sets these (possibly using it's own
wrapper?!?!?)

So...
I'm aware I could go and start changing my existing jsp's to use
setAttribute() instead of the jsp:param tag.  That's an option sure,
but I can't guarantee someone else down the line won't attempt using
jsp:params again.  I'd rather just fix my wrapper to implement
whatever is required to support parameters set using the jsp:param
tag.

I searched the user lists and found a couple of very closely related
posts, e.g. ...
http://marc.info/?l=tomcat-user&m=105840386114978&w=2

... but they didn't really help me solve my problem.  They're also
quite old which makes me think I'm retracing old ground and missing
something obvious here!

How does tomcat handle these parameters?  Is the implementation
specific to tomcat?  Or is it an approach taken by the various web
containers in general?

Thanks for any replies,

Tomás.

================================================
(In following code, I've only added setRequest() as I've been trying
to understand what's going on.  Ditto use of two maps.  I started out
with just the one but have been adding extra bits as I've been
debugging.  I can provide the original simpler wrapper if that's more
appropriate...)

package com.test.filters;

import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.HashMap;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class TestRequestWrapper extends HttpServletRequestWrapper {

  // We use two maps:
  // The first stores the custom parameters that we set in this filter. We keep
  // a record of all custom parameters set so that we may consistently include
  // them, even when another process calls setRequest()
  Map<String,String[]> customParams = new HashMap<String,String[]>();
  // ... then the second is the overall one we will return when asked.  This map
  // will contain both the original request parameters AND any additional/
  // manipulated parameters we happen to have set!
  Map<String,String[]> params       = new HashMap<String,String[]>();

   /**
   * @param request
   */
  @SuppressWarnings("unchecked")
  public TestRequestWrapper(ServletRequest request) {
    super((HttpServletRequest) request);
    // Load up the the request params map into our custom map...
    if (request.getParameterMap() != null) {
     this.params.putAll(request.getParameterMap());
    }
  }

  /* We are happy to let the ServletRequest do all the work EXCEPT where it
   * comes to dealing with parameters.  We must overload ALL the parameter
   * related methods from Servlet request, so when anything downwind of the
   * filter/wrapped request queries the parameters it is looking at our own
   * doctored copy.
   */
  /*
   * @see javax.servlet.ServletRequest#getParameter(java.lang.String)
   */
  public String getParameter(String name) {
    String returnValue = null;
    String[] paramArray = getParameterValues(name);
    if (paramArray != null && paramArray.length > 0){
      returnValue = paramArray[0];
    }
    return returnValue;
  }
  /* (non-Javadoc)
   * @see javax.servlet.ServletRequest#getParameterMap()
   */
  public Map<String, String[]> getParameterMap() {
    return Collections.unmodifiableMap(params);
  }
  /* (non-Javadoc)
   * @see javax.servlet.ServletRequest#getParameterNames()
   */
  public Enumeration<String> getParameterNames() {
    return Collections.enumeration(params.keySet());
  }
  /* (non-Javadoc)
   * @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
   */
  public String[] getParameterValues(String name) {
    String[] result = null;
    String[] temp = (String[])params.get(name);
    if (temp != null){
      result = new String[temp.length];
      System.arraycopy(temp, 0, result, 0, temp.length);
    }
    return result;
  }

  // Empirically, I have observed that setRequest() is called whenever the
  // container does an include or a forward.  I see this called after the
  // dispatcher.forward in the main servlet (front controller) and multiple
  // times for the includes in the jsp's.  As a result, we reload our parameter
  // map every time setRequest() is called, to be sure our manipulated
  // parameters are used for every request/response pair...
  @SuppressWarnings("unchecked")
  public void setRequest(ServletRequest request) {
    super.setRequest(request);

    // Load up the the request params map for this new request.
    this.params.clear();
    if (request.getParameterMap() != null) {
      this.params.putAll(request.getParameterMap());
    }
    // The effect of this call to putAll is equivalent to that of calling
    // put(k, v) on this map once for each mapping from key k to value v in the
    // specified map
    this.params.putAll(customParams);

  }

  /* Now for our magic!  Normally, you cannot set parameters, but now that we
   * control the parameter map, we can do what we like.  Implement two methods
   * allowing us to set the values in the parameter map as we see fit. Sweet!
   */

  /**
   * Sets the a single value for the parameter.  Overwrites any current values.
   * @param name Name of the parameter to set
   * @param value Value of the parameter.
   */
  public void setParameter(String name, String value){
    String[] oneParam = {value};
    setParameter(name, oneParam);
  }

  /**
   * Sets multiple values for a parameter.
   * Overwrites any current values.
   * @param name Name of the parameter to set
   * @param values String[] of values.
   */
  public void setParameter(String name, String[] values){
    // We store set parameters in the custom map.  This means we always have a
    // record of our own 'special' parameters...
    customParams.put(name, values);

    // Then we also put the parameter into the 'live' set so that it will be
    // returned alongside the natural parameters of the original request.
    // If the map previously contained a mapping for this key, the old value is
    // replaced by the specified value.
    params.put(name, values);
  }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message