Package org.apache.catalina.valves

# Class PersistentValve

java.lang.Object
org.apache.catalina.util.LifecycleBase
org.apache.catalina.util.LifecycleMBeanBase
org.apache.catalina.valves.ValveBase
org.apache.catalina.valves.PersistentValve

All Implemented Interfaces:
  `MBeanRegistration`, `Contained`, `JmxEnabled`, `Lifecycle`, `Valve`

public class PersistentValve extends ValveBase
Valve that implements per-request session persistence. It is intended to be used with non-sticky load-balancers and a PersistentManager. The Valve works by loading the session from the Store at the start of the request, the request then updates the session as required and the Valve saves the session to the Store at the end of the request.

To avoid conflicts and/or errors when updating the session store, each session must only be accessed by no more than one concurrent request. The `filter` field can be used to define requests (e.g. those for static resources) that do not need access to the session and can Requests for resources that do not need to access the session and can bypass the session load/save functionality provided by this Valve.

The Valve uses a per session `Semaphore` to ensure that each session is accessed by no more than one request at a time within a single Tomcat instance. The behaviour if multiple requests try to access the session concurrently can be controlled by the `semaphoreFairness`, `semaphoreBlockOnAcquire` and `semaphoreAcquireUninterruptibly` fields. If a request fails to obtain the Semaphore, the response is generated by the `onSemaphoreNotAcquired(Request, Response)` method which, by default, returns a `429` status code.

The per session Semaphores only provide limited protection against concurrent requests within a single Tomcat instance. If multiple requests access the same session concurrently across different Tomcat instances, update conflicts and/or session data loss and/or errors are very likely.

USAGE CONSTRAINTS:

- This Valve must only be used with a PersistentManager
- The client must ensure that no more than one concurrent request accesses a session at any time across all Tomcat instances

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from interface org.apache.catalina.Lifecycle

  `Lifecycle.SingleUse`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected Pattern`
  `filter`

  ### Fields inherited from class org.apache.catalina.valves.ValveBase

  `asyncSupported, container, containerLog, next, sm`

  ### Fields inherited from class org.apache.catalina.util.LifecycleMBeanBase

  `mserver`

  ### Fields inherited from interface org.apache.catalina.Lifecycle

  `AFTER_DESTROY_EVENT, AFTER_INIT_EVENT, AFTER_START_EVENT, AFTER_STOP_EVENT, BEFORE_DESTROY_EVENT, BEFORE_INIT_EVENT, BEFORE_START_EVENT, BEFORE_STOP_EVENT, CONFIGURE_START_EVENT, CONFIGURE_STOP_EVENT, PERIODIC_EVENT, START_EVENT, STOP_EVENT`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `PersistentValve()`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `String`
  `getFilter()`
  `void`
  `invoke(Request request, Response response)`
  Perform request processing as required by this Valve.
  `protected boolean`
  `isRequestWithoutSession(String uri)`
  `boolean`
  `isSemaphoreAcquireUninterruptibly()`
  If a thread is blocking to acquire a per session Semaphore, can that thread be interrupted?
  `boolean`
  `isSemaphoreBlockOnAcquire()`
  If a thread attempts to acquire the per session Semaphore while it is being used by another request, should the thread block to wait for the Semaphore or should the request be rejected?
  `boolean`
  `isSemaphoreFairness()`
  If multiple threads attempt to acquire the same per session Semaphore, will permits be granted in the same order they were requested?
  `protected boolean`
  `isSessionStale(Session session, long timeNow)`
  Indicate whether the session has been idle for longer than its expiration date as of the supplied time.
  `protected void`
  `onSemaphoreNotAcquired(Request request, Response response)`
  Handle the case where a semaphore cannot be obtained.
  `void`
  `setContainer(Container container)`
  Set the `Container` with which this instance is associated.
  `void`
  `setFilter(String filter)`
  `void`
  `setSemaphoreAcquireUninterruptibly(boolean semaphoreAcquireUninterruptibly)`
  Configure whether a thread blocking to acquire a per session Semaphore can be interrupted.
  `void`
  `setSemaphoreBlockOnAcquire(boolean semaphoreBlockOnAcquire)`
  Configure whether a thread should block and wait for the per session Semaphore or reject the request if the Semaphore is being used by another request.
  `void`
  `setSemaphoreFairness(boolean semaphoreFairness)`
  Configure whether the per session Semaphores will handle granting of permits in the same order they were requested if multiple threads attempt to acquire the same Semaphore.

  ### Methods inherited from class org.apache.catalina.valves.ValveBase

  `backgroundProcess, getContainer, getDomainInternal, getNext, getObjectNameKeyProperties, initInternal, isAsyncSupported, setAsyncSupported, setNext, startInternal, stopInternal, toString`

  ### Methods inherited from class org.apache.catalina.util.LifecycleMBeanBase

  `destroyInternal, getDomain, getObjectName, postDeregister, postRegister, preDeregister, preRegister, register, setDomain, unregister, unregister`

  ### Methods inherited from class org.apache.catalina.util.LifecycleBase

  `addLifecycleListener, destroy, findLifecycleListeners, fireLifecycleEvent, getState, getStateName, getThrowOnFailure, init, removeLifecycleListener, setState, setState, setThrowOnFailure, start, stop`

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

- ## Field Details

  - ### filter

    protected Pattern filter

- ## Constructor Details

  - ### PersistentValve

    public PersistentValve()

- ## Method Details

  - ### setContainer

    public void setContainer(Container container)
    Description copied from interface: `Contained`
    Set the `Container` with which this instance is associated.
    Specified by:
      `setContainer` in interface `Contained`
    Overrides:
      `setContainer` in class `ValveBase`
    Parameters:
      `container` - The Container instance with which this instance is to be associated, or `null` to disassociate this instance from any Container

  - ### invoke

    public void invoke(Request request, Response response) throws IOException, ServletException
    Description copied from interface: `Valve`

    Perform request processing as required by this Valve.

    An individual Valve MAY perform the following actions, in the specified order:

    - Examine and/or modify the properties of the specified Request and Response.
    - Examine the properties of the specified Request, completely generate the corresponding Response, and return control to the caller.
    - Examine the properties of the specified Request and Response, wrap either or both of these objects to supplement their functionality, and pass them on.
    - If the corresponding Response was not generated (and control was not returned, call the next Valve in the pipeline (if there is one) by executing `getNext().invoke()`.
    - Examine, but not modify, the properties of the resulting Response (which was created by a subsequently invoked Valve or Container).

    A Valve MUST NOT do any of the following things:

    - Change request properties that have already been used to direct the flow of processing control for this request (for instance, trying to change the virtual host to which a Request should be sent from a pipeline attached to a Host or Context in the standard implementation).
    - Create a completed Response AND pass this Request and Response on to the next Valve in the pipeline.
    - Consume bytes from the input stream associated with the Request, unless it is completely generating the response, or wrapping the request before passing it on.
    - Modify the HTTP headers included with the Response after the `getNext().invoke()` method has returned.
    - Perform any actions on the output stream associated with the specified Response after the `getNext().invoke()` method has returned.
    Parameters:
      `request` - The servlet request to be processed
      `response` - The servlet response to be created
    Throws:
      `IOException` - if an input/output error occurs, or is thrown by a subsequently invoked Valve, Filter, or Servlet
      `ServletException` - if a servlet error occurs, or is thrown by a subsequently invoked Valve, Filter, or Servlet

  - ### onSemaphoreNotAcquired

    protected void onSemaphoreNotAcquired(Request request, Response response) throws IOException
    Handle the case where a semaphore cannot be obtained. The default behaviour is to return a 429 (too many requests) status code.
    Parameters:
      `request` - The request that will not be processed
      `response` - The response that will be used for this request
    Throws:
      `IOException` - If an I/O error occurs while working with the request or response

  - ### isSessionStale

    protected boolean isSessionStale(Session session, long timeNow)
    Indicate whether the session has been idle for longer than its expiration date as of the supplied time.
    Parameters:
      `session` - The session to check
      `timeNow` - The current time to check for
    Returns:
      `true` if the session is past its expiration

  - ### isRequestWithoutSession

    protected boolean isRequestWithoutSession(String uri)

  - ### getFilter

    public String getFilter()

  - ### setFilter

    public void setFilter(String filter)

  - ### isSemaphoreFairness

    public boolean isSemaphoreFairness()
    If multiple threads attempt to acquire the same per session Semaphore, will permits be granted in the same order they were requested?
    Returns:
      `true` if fairness is enabled, otherwise `false`

  - ### setSemaphoreFairness

    public void setSemaphoreFairness(boolean semaphoreFairness)
    Configure whether the per session Semaphores will handle granting of permits in the same order they were requested if multiple threads attempt to acquire the same Semaphore.
    Parameters:
      `semaphoreFairness` - `true` if permits should be granted in the same order they are requested, otherwise `false`

  - ### isSemaphoreBlockOnAcquire

    public boolean isSemaphoreBlockOnAcquire()
    If a thread attempts to acquire the per session Semaphore while it is being used by another request, should the thread block to wait for the Semaphore or should the request be rejected?
    Returns:
      `true` if the thread should block, otherwise `false` to reject the concurrent request

  - ### setSemaphoreBlockOnAcquire

    public void setSemaphoreBlockOnAcquire(boolean semaphoreBlockOnAcquire)
    Configure whether a thread should block and wait for the per session Semaphore or reject the request if the Semaphore is being used by another request.
    Parameters:
      `semaphoreBlockOnAcquire` - `true` to block, otherwise `false`

  - ### isSemaphoreAcquireUninterruptibly

    public boolean isSemaphoreAcquireUninterruptibly()
    If a thread is blocking to acquire a per session Semaphore, can that thread be interrupted?
    Returns:
      `true` if the thread can not be interrupted, otherwise `false`.

  - ### setSemaphoreAcquireUninterruptibly

    public void setSemaphoreAcquireUninterruptibly(boolean semaphoreAcquireUninterruptibly)
    Configure whether a thread blocking to acquire a per session Semaphore can be interrupted.
    Parameters:
      `semaphoreAcquireUninterruptibly` - `true` if the thread can not be interrupted, otherwise `false`.