Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2007

Tip: Looking for answers? Try searching our database.

Question on filter

Thread view: 
Ravion - 03 Feb 2007 23:00 GMT
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;

}
Lew - 04 Feb 2007 00:55 GMT
> 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. .  .
[quoted text clipped - 4 lines]
> 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


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.