HTTPClient.IdempotentSequence Maven / Gradle / Ivy
Show all versions of grinder-httpclient Show documentation
/*
* @(#)IdempotentSequence.java 0.3-3 06/05/2001
*
* This file is part of the HTTPClient package
* Copyright (C) 1996-2001 Ronald Tschalär
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA
*
* For questions, suggestions, bug-reports, enhancement-requests etc.
* I may be contacted at:
*
* [email protected]
*
* The HTTPClient's home page is located at:
*
* http://www.innovation.ch/java/HTTPClient/
*
*/
package HTTPClient;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* This class checks whether a sequence of requests is idempotent. This
* is used to determine which requests may be automatically retried. This
* class also serves as a central place to record which methods have side
* effects and which methods are idempotent.
*
*
Note: unknown methods (i.e. a method which is not HEAD, GET, POST, PUT,
* DELETE, OPTIONS, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, or
* UNLOCK) are treated conservatively, meaning they are assumed to have side
* effects and are not idempotent.
*
*
Usage:
*
* IdempotentSequence seq = new IdempotentSequence();
* seq.add(r1);
* ...
* if (seq.isIdempotent(r1)) ...
* ...
*
*
* @version 0.3-3 06/05/2001
* @author Ronald Tschalär
*/
class IdempotentSequence
{
/** method number definitions */
private static final int UNKNOWN = 0,
HEAD = 1,
GET = 2,
POST = 3,
PUT = 4,
DELETE = 5,
OPTIONS = 6,
TRACE = 7,
// DAV methods
PROPFIND = 8,
PROPPATCH = 9,
MKCOL = 10,
COPY = 11,
MOVE = 12,
LOCK = 13,
UNLOCK = 14;
/** these are the history of previous requests */
private int[] m_history;
private String[] r_history;
private int m_len, r_len;
/** trigger analysis of threads */
private boolean analysis_done = false;
private Hashtable threads = new Hashtable();
// Constructors
/**
* Start a new sequence of requests.
*/
public IdempotentSequence()
{
m_history = new int[10];
r_history = new String[10];
m_len = 0;
r_len = 0;
}
// Methods
/**
* Add the request to the end of the list of requests. This is used
* to build the complete sequence of requests before determining
* whether the sequence is idempotent.
*
* @param req the next request
*/
public void add(Request req)
{
if (m_len >= m_history.length)
m_history = Util.resizeArray(m_history, m_history.length+10);
m_history[m_len++] = methodNum(req.getMethod());
if (r_len >= r_history.length)
r_history = Util.resizeArray(r_history, r_history.length+10);
r_history[r_len++] = req.getRequestURI();
}
/**
* Is this request part of an idempotent sequence? This method must
* not be called before all requests have been added to this
* sequence; similarly, add() must not be called
* after this method was invoked.
*
* We split up the sequence of requests into individual sub-sequences,
* or threads, with all requests in a thread having the same request-URI
* and no two threads having the same request-URI. Each thread is then
* marked as idempotent or not according to the following rules:
*
*
* - If any method is UNKNOWN then the thread is not idempotent;
*
- else, if no method has side effects then the thread is idempotent;
*
- else, if the first method has side effects and is complete then
* the thread is idempotent;
*
- else, if the first method has side effects, is not complete,
* and no other method has side effects then the thread is idempotent;
*
- else the thread is not idempotent.
*
*
* The major assumption here is that the side effects of any method
* only apply to resource specified. E.g. a "PUT /barbara.html"
* will only affect the resource "/barbara.html" and nothing else.
* This assumption is violated by POST of course; however, POSTs are
* not pipelined and will therefore never show up here.
*
* @param req the request
*/
public boolean isIdempotent(Request req)
{
if (!analysis_done)
do_analysis();
return ((Boolean) threads.get(req.getRequestURI())).booleanValue();
}
private static final Object INDET = new Object();
private void do_analysis()
{
for (int idx=0; idx