Question on filter

Discussion in 'Java' started by Ravion, Feb 3, 2007.

  1. Ravion

    Ravion Guest

    Dear ll,

    I could not get any response from other group, so posting it here:-

    Please find below a code I found in onjava regarding a Filter which avoids
    multiple submits. Basically it queues the requests and always overwrites the
    last request with the current waiting request in queue. Hence even if we
    press 10 times, only first and last requests will be filtered. Its a nice
    program. .

    My question is how can we change this program, so that even the last request
    will not be processed ? I do not want the processing to happen even two
    times. I want to restrct the processing to only one time.**note that I do
    not prefer a Java script client solution **. I tried many ways, but hits
    balnk page or some exceptions. Please help ..

    Best regards,
    Ravi

    -------



    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.LinkedList;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;

    public class SiteReentrantFilter implements Filter{


    /**
    * Use this filter to synchronize requests to your web application and
    * reduce the maximum load that each individual user can put on your
    * web application. Requests will be synchronized per session. When more
    * than one additional requests are made while a request is in process,
    * only the most recent of the additional requests will actually be
    * processed.
    * <p>
    * If a user makes two requests, A and B, then A will be processed first
    * while B waits. When A finishes, B will be processed.
    * <p>
    * If a user makes three or more requests (e.g. A, B, and C), then the
    * first will be processed (A), and then after it finishes the last will
    * be processed (C), and any intermediate requests will be skipped (B).
    * <p>
    * There are two additional limitiations:
    * <ul>
    * <li>Requests will be excluded from filtering if their URI matches
    * one of the exclusion patterns. There will be no synchronization
    * performed if a request matches one of those patterns.</li>
    * <li>Requests wait a maximum of 5 seconds, which can be overridden
    * per URI pattern in the filter's configuration.</li>
    * </ul>
    *
    */

    /**
    * Initialize this filter by reading its configuration parameters
    *
    * @param config Configuration from web.xml file
    */
    public void init( FilterConfig config ) throws ServletException
    {
    // parse all of the initialization parameters, collecting the exclude
    // patterns and the max wait parameters
    Enumeration enum = config.getInitParameterNames();
    excludePatterns = new LinkedList();
    maxWaitDurations = new HashMap();
    while( enum.hasMoreElements() )
    {
    String paramName = ( String )enum.nextElement();
    String paramValue = config.getInitParameter( paramName );
    if( paramName.startsWith( "excludePattern" ) )
    {
    // compile the pattern only this once
    Pattern excludePattern = Pattern.compile( paramValue );
    excludePatterns.add( excludePattern );
    }
    else if( paramName.startsWith( "maxWaitMilliseconds." ) )
    {
    // the delay gets parsed from the parameter name
    String durationString = paramName.substring(
    "maxWaitMilliseconds.".length() );
    int endDuration = durationString.indexOf( '.' );
    if( endDuration != -1 )
    {
    durationString = durationString.substring( 0, endDuration );
    }
    Long duration = new Long( durationString );

    // compile the corresponding pattern, and store it with this delay
    in the map
    Pattern waitPattern = Pattern.compile( paramValue );
    maxWaitDurations.put( waitPattern, duration );
    }
    }
    }

    /**
    * Called with the filter is no longer needed.
    */
    public void destroy()
    {
    // there is nothing to do
    }

    /**
    * Synchronize the request and then either process it or skip it,
    * depending on what other requests current exist for this session.
    * See the description of this class for more details.
    */
    public void doFilter(
    ServletRequest request,
    ServletResponse response,
    FilterChain chain )
    throws IOException, ServletException
    {
    HttpServletRequest httpRequest = (HttpServletRequest)request;
    HttpServletResponse httpResponse = (HttpServletResponse)response;
    HttpSession session = httpRequest.getSession();

    // if this request is excluded from the filter, then just process it
    if( !isFilteredRequest( httpRequest ) )
    {
    chain.doFilter( request, response );
    return;
    }

    synchronized( getSynchronizationObject( session ) )
    {
    // if another request is being processed, then wait
    if( isRequestInProcess( session ) )
    {
    // Put this request in the queue and wait
    enqueueRequest( httpRequest, httpResponse );
    if( !waitForRelease( httpRequest ) )
    {
    // this request was replaced in the queue by another request,
    // so it need not be processed
    return;
    }
    }

    // lock the session, so that no other requests are processed until
    this one finishes
    setRequestInProgress( httpRequest );
    }

    // process this request, and then release the session lock regardless of
    // any exceptions thrown farther down the chain.
    try
    {
    chain.doFilter( request, response );
    }
    finally
    {
    releaseQueuedRequest( httpRequest );
    }
    }

    /**
    * Get a synchronization object for this session
    *
    * @param session
    */
    private static synchronized Object getSynchronizationObject(HttpSession
    session)
    {
    // get the object from the session. If it does not yet exist,
    // then create one.
    Object syncObj = session.getAttribute( SYNC_OBJECT_KEY );
    if( syncObj == null )
    {
    syncObj = new Object();
    session.setAttribute( SYNC_OBJECT_KEY, syncObj );
    }
    return syncObj;
    }

    /**
    * Record that a request is in process so that the filter blocks
    additional
    * requests until this one finishes.
    *
    * @param request
    */
    private void setRequestInProgress(HttpServletRequest request)
    {
    HttpSession session = request.getSession();
    session.setAttribute( REQUEST_IN_PROCESS, request );
    }

    /**
    * Release the next waiting request, because the current request
    * has just finished.
    *
    * @param request The request that just finished
    */
    private void releaseQueuedRequest( HttpServletRequest request )
    {
    HttpSession session = request.getSession();
    synchronized( getSynchronizationObject( session ) )
    {
    // if this request is still the current one (i.e., it didn't run for
    too
    // long and result in another request being processed), then clear it
    // and thus release the lock
    if( session.getAttribute( REQUEST_IN_PROCESS ) == request )
    {
    session.removeAttribute( REQUEST_IN_PROCESS );
    getSynchronizationObject( session ).notify();
    }
    }
    }

    /**
    * Is this server currently processing another request for this session?
    *
    * @param session The request's session
    * @return true if the server is handling another request for
    this session
    */
    private boolean isRequestInProcess( HttpSession session )
    {
    return session.getAttribute( REQUEST_IN_PROCESS ) != null;
    }

    /**
    * Wait for this server to finish with its current request so that
    * it can begin processing our next request. This method also detects if
    * its request is replaced by another request in the queue.
    *
    * @param request Wait for this request to be ready to run
    * @return true if this request may be processed, or false if this
    * request was replaced by another in the queue.
    */
    private boolean waitForRelease( HttpServletRequest request )
    {
    HttpSession session = request.getSession();

    // wait for the currently running request to finish, or until this
    // thread has waited the maximum amount of time
    try
    {
    getSynchronizationObject( session ).wait( getMaxWaitTime( request ) );
    }
    catch( InterruptedException ie )
    {
    return false;
    }

    // This request can be processed now if it hasn't been replaced
    // in the queue

    return request == session.getAttribute( REQUEST_QUEUE );
    }

    /**
    * Put a new request in the queue. This new request will replace
    * any other requests that were waiting.
    *
    * @param request The request to queue
    */
    private void enqueueRequest( HttpServletRequest request ,
    HttpServletResponse response)
    {
    HttpSession session = request.getSession();


    // Put this request in the queue, replacing whoever was there before, if
    no match
    session.setAttribute( REQUEST_QUEUE,request );


    // if another request was waiting, notify it so it can discover that
    // it was replaced
    getSynchronizationObject( session ).notify();
    }

    /**
    * What is the maximum wait time (in milliseconds) for this request
    *
    * @param request
    * @return Maximum number of milliseconds to hold this request in the
    queue
    */
    private long getMaxWaitTime( HttpServletRequest request )
    {
    // look for a Pattern that matches the request's path
    String path = request.getRequestURI();
    Iterator patternIter = maxWaitDurations.keySet().iterator();
    while( patternIter.hasNext() )
    {
    Pattern p = (Pattern)patternIter.next();
    Matcher m = p.matcher( path );
    if( m.matches() )
    {
    // this pattern matches. At most, how long can this request wait?
    Long maxDuration = (Long)maxWaitDurations.get( p );
    return maxDuration.longValue();
    }
    }

    // If no pattern matches the path, return the default value
    return DEFAULT_DURATION;
    }

    /**
    * Look through the filter's configuration, and determine whether or not
    it
    * should synchronize this request with others.
    *
    * @param httpRequest
    * @return
    */
    private boolean isFilteredRequest(HttpServletRequest request)
    {
    // iterate through the exclude patterns. If one matches this path,
    // then the request is excluded.
    String path = request.getRequestURI();
    Iterator patternIter = excludePatterns.iterator();
    while( patternIter.hasNext() )
    {
    Pattern p = (Pattern)patternIter.next();
    Matcher m = p.matcher( path );
    if( m.matches() )
    {
    // at least one of the patterns excludes this request
    return false;
    }
    }

    // this path is not excluded
    return true;
    }

    /** A list of Pattern objects that match paths to exclude */
    private LinkedList excludePatterns;

    /** A map from Pattern to max wait duration (Long objects) */
    private HashMap maxWaitDurations;

    /** The session attribute key for the request currently being processed */
    private final static String REQUEST_IN_PROCESS
    = "SiteReentrantFilter.requestInProcess";

    /** The session attribute key for the request currently waiting in the
    queue */
    private final static String REQUEST_QUEUE
    = "SiteReentrantFilter.requestQueue";

    /** The session attribute key for the synchronization object */
    private final static String SYNC_OBJECT_KEY =
    "SiteReentrantFilter.sessionSync";

    /** The default maximum number of milliseconds to wait for a request */
    private final static long DEFAULT_DURATION = 5000;


    }
    Ravion, Feb 3, 2007
    #1
    1. Advertising

  2. Ravion

    Lew Guest

    Ravion wrote:
    > I could not get any response from other group, so posting it here:-


    Just to help out that other group, you should have considered responding to
    your original post on that group, cross-posted to here in order to widen the
    audience without losing the original thread.

    > Please find below a code I found in onjava regarding a Filter which avoids
    > multiple submits. . .
    >
    > My question is how can we change this program, so that even the last request
    > will not be processed ? I do not want the processing to happen even two
    > times. I want to restrct the processing to only one time.**note that I do
    > not prefer a Java script client solution **. I tried many ways, but hits
    > balnk page or some exceptions. Please help ..


    You might find it useful to try the "token pattern":
    <http://www.javaworld.com/javaworld/javatips/jw-javatip136.html>
    and others, googlable.

    - Lew
    Lew, Feb 4, 2007
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ron Vecchi
    Replies:
    1
    Views:
    660
    Ron Vecchi
    Jul 27, 2003
  2. Ron Vecchi
    Replies:
    0
    Views:
    384
    Ron Vecchi
    Jul 30, 2003
  3. =?Utf-8?B?TWlrZQ==?=

    dataset filter question

    =?Utf-8?B?TWlrZQ==?=, Oct 13, 2004, in forum: ASP .Net
    Replies:
    7
    Views:
    3,164
    Greg Burns
    Oct 14, 2004
  4. =?Utf-8?B?YW5kcmV3MDA3?=

    question row filter (more of sql query question)

    =?Utf-8?B?YW5kcmV3MDA3?=, Oct 5, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    929
    Scott Allen
    Oct 6, 2005
  5. zax75
    Replies:
    1
    Views:
    1,084
Loading...

Share This Page