Package hirondelle.web4j.request

Source Code of hirondelle.web4j.request.RequestParameter

package hirondelle.web4j.request;

import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.servlet.ServletConfig;

import hirondelle.web4j.action.Action;
import hirondelle.web4j.model.ModelCtorException;
import hirondelle.web4j.model.ModelFromRequest;
import hirondelle.web4j.model.ModelUtil;
import hirondelle.web4j.readconfig.InitParam;
import hirondelle.web4j.security.ApplicationFirewall;
import hirondelle.web4j.util.Util;

/**
<span class="highlight">Request parameter as a name and
(usually) an associated <em>regular expression</em>.</span>

<P>This class does not <em>directly</em> provide access to the parameter <em>value</em>.
For such services, please see {@link RequestParser} and {@link ModelFromRequest}.
 
<P>This class separates request parameters into two kinds : file upload request
parameters, and all others (here called "regular" request parameters).
 
<P><b><a name="Regular">Regular Request Parameters</a></b><br>
Regular request parameters are associated with :
<ul>
<li>a name, corresponding to both an underlying HTTP request parameter name, and
an underlying control name - see <a href="#NamingConvention">naming convention</a>.
<li>a regular expression, used by {@link ApplicationFirewall} to perform
<a href="ApplicationFirewall.html#HardValidation">hard validation</a> 
</ul>
<P><b><a name="FileUpload">File Upload Request Parameters</a></b><br>
Files are uploaded using forms having :
<ul>
<li> <tt>method="POST"</tt>
<li> <tt>enctype="multipart/form-data"</tt>
<li> an <tt>&lt;INPUT type="file"&gt;</tt> control
</ul>
<P>In addition, note that the Servlet API does <em>not</em> have extensive services for
processing file upload parameters. It is likely best to use a third party tool for
that task.
<P>File upload request parameters, <em>as represented by this class</em>, have only a
name associated with them, and no regular expression. This is because WEB4J
cannot perform <a href="ApplicationFirewall.html#HardValidation">hard validation</a> 
on the value of a file upload parameter - since the user may select any file whatsoever,
validation of file contents can only be treated
as a <a href="ApplicationFirewall.html#SoftValidation">soft validation</a>. If there is a
problem, the response to the user must be polished, as part of the normal operation of
the application. 
<P>As an example, an {@link Action} might perform
<a href="ApplicationFirewall.html#SoftValidation">soft validation</a> on a file upload parameter
for these items :
<ul>  
<li>file size does not exceed a maximum value
<li>MIME type matches a regular expression 
<li>file name matches a regular expression
<li>text file content may be matched to a regular expression
</ul>
<P><b><a name="NamingConvention">Naming Convention</a></b><br>
<span class="highlight">Parameter names are usually not arbitrary in WEB4J.</span>
Instead, a simple convention is used which allows for automated mapping between
request parameter names and corresponding <tt>getXXX</tt> methods of Model Objects 
(see {@link hirondelle.web4j.ui.tag.Populate}). For example, a parameter
named <tt>'Birth Date'</tt> (or <tt>'birthDate'</tt>) is mapped to a method named
<tt>getBirthDate()</tt> when prepopulating a form with the contents of
a Model Object. (The <tt>'Birth Date'</tt> naming style is recommended, since it
has this advantage : when messages regarding form input are presented to the user,
the control name may be used directly, without trivial mapping 
of a 'coder-friendly' parameter name into more user-friendly text.)
 
<P> Some parameters - notably those passed to <tt>Template.jsp</tt> - are not
processed at all by the <tt>Controller</tt>, but are used directly in JSPs
instead. Such parameters do not undergo
<a href="ApplicationFirewall.html#HardValidation">hard validation</a> by the
{@link hirondelle.web4j.security.ApplicationFirewall}, and are not represented by this class.
<P> See {@link java.util.regex.Pattern} for more information on regular expressions.
*/
public final class RequestParameter {
 
  /**
   <P>Called by the framework upon startup.
  
   <P>Fetches the setting named <tt>MaxRequestParamValueSize</tt> in <tt>web.xml</tt>.
   This setting is used by {@link #withLengthCheck(String)}.
  */
  public static void init(ServletConfig aConfig){
    MAX_SIZE = getMaxSize(fMAX_SIZE, aConfig);
    fLogger.fine("Max size of request parameter values, from web.xml : " + MAX_SIZE);
  }

  /**
   Return a <a href="#Regular">regular parameter</a> hard-validated only for
   name and size.
  
   <P>The size is taken from the <tt>MaxRequestParamValueSize</tt> setting in <tt>web.xml</tt>.
   
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
  */
  public static RequestParameter withLengthCheck(String aName){
    String regex = "(.){0," + MAX_SIZE + "}";
    Pattern lengthPattern = Pattern.compile(regex, Pattern.DOTALL);
    return withRegexCheck(aName, lengthPattern);
  }
 
  /**
   Return a <a href="#Regular">regular parameter</a> hard-validated for name and
   for value matching a regular expression.
  
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
   @param aValueRegex regular expression for doing hard validation of the request
   parameter value(s).
  */
  public static RequestParameter withRegexCheck(String aName, Pattern aValueRegex){
    return new RequestParameter(aName, aValueRegex);   
  }
 
  /**
   Return a <a href="#Regular">regular parameter</a> hard-validated for name and
   for value matching a regular expression.
  
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
   @param aValueRegex regular expression for doing hard validation of the request
   parameter value(s).
  */
  public static RequestParameter withRegexCheck(String aName, String aValueRegex){
    return new RequestParameter(aName, aValueRegex);   
  }
 
  /**
   Constructor for a <a href="#FileUpload">file upload</a> request parameter.
  
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
  */
  public static RequestParameter forFileUpload(String aName){
    return new RequestParameter(aName);
  }
 
  /** Return the request parameter name.  */
  public String getName(){
    return fName;
  }
  
  /**
   Return the regular expression associated with this <tt>RequestParameter</tt>.
  
   <P>This regular expression is used to perform
   <a href="ApplicationFirewall.html#HardValidation">hard validation</a> of this parameter's value(s).
  
   <P>This method will return <tt>null</tt> only for <a href="#FileUpload">file upload</a> parameters.
  */
  public Pattern getRegex(){
    return fRegex;
  }
 
  /**
   Return <tt>true</tt> only if {@link #forFileUpload} was used to build this object.
  */
  public boolean isFileUploadParameter() {
    return ! fIsRegularParameter;
  }
 
  /**
   Return <tt>true</tt> only if <tt>aRawParamValue</tt> satisfies the regular expression
   {@link #getRegex()}, <em>or</em> if this is a <a href="#FileUpload">file upload</a>
   request parameter.
  
   <P>Always represents a <a href="ApplicationFirewall.html#HardValidation">hard validation</a>, not a
   soft validation.
  */
  public boolean isValidParamValue(String aRawParamValue){
    boolean result = false;
    if ( isFileUploadParameter() ){
      result = true;  
    }
    else {
      result = Util.matches(fRegex, aRawParamValue);
    }
    return result;
  }
 
  @Override public boolean equals(Object aThat){
    if (this == aThat) return true;
    if ( !(aThat instanceof RequestParameter) ) return false;
    RequestParameter that = (RequestParameter)aThat;
    return ModelUtil.equalsFor(this.getSignificantFields(), that.getSignificantFields());
  }
 
  @Override public int hashCode(){
    return ModelUtil.hashCodeFor(getSignificantFields());
  }

  /** Intended for debugging only.  */
  @Override public String toString() {
    String result = null;
    if ( isFileUploadParameter() ) {
      result = "Name[File Upload]: " + fName; 
    }
    else {
      result = "Name:" + fName + " Regex:" + fRegex; 
    }
    return result;
  }
 
  // PRIVATE //
  private final String fName;
  private Pattern fRegex; //Patterns are immutable
  private final boolean fIsRegularParameter;
 
  /**
   Max size of a valid HTTP request parameter value, in bytes. Pulled in from web.xml.
  */
  private static int MAX_SIZE;
  private static final InitParam fMAX_SIZE = new InitParam("MaxRequestParamValueSize", "51200");
  private static final Logger fLogger = Util.getLogger(RequestParameter.class);
 
  private static int getMaxSize(InitParam aInitParam, ServletConfig aConfig){
    int result = Integer.parseInt(
      aInitParam.fetch(aConfig).getValue()
    );
    if ( result < 1000 ) {
      throw new IllegalArgumentException(
        "Configured value of " + result + " in web.xml for " +
        aInitParam.getName() +
        " is too low. Please see web.xml for more information."
      );
    }
    return result;
  }
 
  /**
   Constructor for a <a href="#Regular">"regular"</a> request parameter.
  
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
   @param aRegex regular expression for doing hard validation of the request
   parameter value(s).
  */
  private RequestParameter(String aName, String aRegex) {
    this(aName, Pattern.compile(aRegex));
    validateState();
  }
  
  /**
   Constructor for a <a href="#Regular">"regular"</a> request parameter.
   
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
   @param aRegex regular expression for doing hard validation of the request
   parameter value(s).
  */
  private RequestParameter(String aName, Pattern aRegex) {
    fName = aName;
    fRegex = aRegex;
    fIsRegularParameter = true;
    validateState();
  }
 
  /**
   Constructor for a <a href="#FileUpload">file upload</a> request parameter.
   
   @param aName name of the underlying HTTP request parameter. See
   <a href="#NamingConvention">naming convention</a>.
  */
  private RequestParameter(String aName) {
    fName = aName;
    fIsRegularParameter = false;
    validateState();
  }
  private void validateState(){
    //use the model ctor exception only to gather errors together
    //it is never actually thrown.
    ModelCtorException ex = new ModelCtorException();
    if ( ! Util.textHasContent(fName) ){
      ex.add("Name must have content.");
    }
    if ( fIsRegularParameter && (fRegex == null || ! Util.textHasContent(fRegex.pattern()) ) ){
      ex.add("For regular request parameters, regex pattern must be present.");
    }
    if ( ! fIsRegularParameter && fRegex != null  ){
      ex.add("For file upload parameters, regex pattern must be null.");
    }
    if ( ex.isNotEmpty() ) {
      throw new IllegalArgumentException(ex.getMessages().toString());
    }
  }
 
  private Object[] getSignificantFields(){
    return new Object[] {fName, fRegex};
  }
}
TOP

Related Classes of hirondelle.web4j.request.RequestParameter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.