Class BreakpointMatcherRegistry

java.lang.Object
org.mockserver.mock.breakpoint.BreakpointMatcherRegistry

public class BreakpointMatcherRegistry extends Object
Process-wide registry of breakpoint matchers. Each entry describes a request matcher and a set of phases; when a forwarded exchange matches, it is paused at the corresponding phase for interactive inspection/modification.

Thread-safe via a single CopyOnWriteArrayList as the source of truth. This is ideal for the access pattern here: reads (findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase)) are frequent and on the data plane (including the Netty event loop), while writes (register(org.mockserver.model.RequestDefinition, java.util.Set<org.mockserver.mock.breakpoint.BreakpointPhase>, org.mockserver.configuration.Configuration, org.mockserver.logging.MockServerLogger), remove(java.lang.String), clear()) are rare control-plane operations. A single structure means register/remove/clear are atomic with respect to a concurrent findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase) — there is no window in which two backing collections can disagree.

Event-loop safety: findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase) is designed to be called on the Netty event loop for stream-frame phases. When the registry is empty, it returns null immediately via a single CopyOnWriteArrayList.isEmpty() check (zero allocation). When non-empty, it iterates a stable snapshot of the prebuilt matchers without any blocking or allocation beyond the matcher's own match logic.

  • Constructor Details

    • BreakpointMatcherRegistry

      public BreakpointMatcherRegistry()
  • Method Details

    • getInstance

      public static BreakpointMatcherRegistry getInstance()
    • register

      public String register(RequestDefinition matcher, Set<BreakpointPhase> phases, Configuration configuration, MockServerLogger logger)
      Registers a new breakpoint matcher without an owner client (for tests only). In production, the REST endpoint requires a clientId; this overload exists for unit tests that exercise the registry directly.
      Parameters:
      matcher - the request definition to match against
      phases - the set of phases at which matching exchanges should break
      configuration - the active server configuration (passed to MatcherBuilder)
      logger - the server logger (passed to MatcherBuilder)
      Returns:
      the assigned UUID id for the registered breakpoint
    • register

      public String register(RequestDefinition matcher, Set<BreakpointPhase> phases, String clientId, Configuration configuration, MockServerLogger logger)
      Registers a new breakpoint matcher with a required owner clientId.
      See Also:
    • register

      public String register(RequestDefinition matcher, Set<BreakpointPhase> phases, String clientId, Integer skipCount, Configuration configuration, MockServerLogger logger)
      Registers a new breakpoint matcher with a required owner clientId and an optional skip-count for conditional (Nth-hit) breakpoints.

      The clientId identifies the callback WebSocket client that owns this breakpoint. Matched exchanges are dispatched over the callback WebSocket to that client for interactive resolution.

      The optional skipCount delays the first pause: the breakpoint still matches on every hit but only pauses once it has been hit more than skipCount times. null (or a non-positive value) means pause on every hit (legacy behaviour).

      Parameters:
      matcher - the request definition to match against
      phases - the set of phases at which matching exchanges should break
      clientId - the callback WS client that owns this breakpoint (required in production)
      skipCount - the number of matching hits to skip before pausing, or null to pause every time
      configuration - the active server configuration (passed to MatcherBuilder)
      logger - the server logger (passed to MatcherBuilder)
      Returns:
      the assigned UUID id for the registered breakpoint
    • register

      public String register(RequestDefinition matcher, Set<BreakpointPhase> phases, String clientId, Integer skipCount, Integer responseStatusCodeMin, Integer responseStatusCodeMax, String responseBodyContains, Configuration configuration, MockServerLogger logger)
      Registers a new breakpoint matcher with a required owner clientId, an optional skip-count for conditional (Nth-hit) breakpoints, and optional response-content conditions that gate whether a RESPONSE-phase breakpoint pauses.

      The response conditions (responseStatusCodeMin/responseStatusCodeMax for an inclusive status-code range, and responseBodyContains for a regex searched within the response body) are only evaluated at the response phase (the response is not known at the request phase). When set, the breakpoint pauses only when the response satisfies all configured conditions. When all are null (the default) the breakpoint pauses regardless of response content (legacy behaviour).

      Parameters:
      matcher - the request definition to match against
      phases - the set of phases at which matching exchanges should break
      clientId - the callback WS client that owns this breakpoint (required in production)
      skipCount - the number of matching hits to skip before pausing, or null to pause every time
      responseStatusCodeMin - inclusive lower bound of the response status-code condition, or null
      responseStatusCodeMax - inclusive upper bound of the response status-code condition, or null
      responseBodyContains - a regex searched (find semantics) within the response body, or null
      configuration - the active server configuration (passed to MatcherBuilder)
      logger - the server logger (passed to MatcherBuilder)
      Returns:
      the assigned UUID id for the registered breakpoint
    • findMatch

      public BreakpointMatcher findMatch(RequestDefinition request, BreakpointPhase phase)
      Finds the first registered breakpoint whose phases contain the given phase AND whose prebuilt matcher matches the given request AND which should pause for this hit.

      Returns null if the registry is empty or no matcher matches. This method is allocation-light and safe to call on the Netty event loop.

      Conditional (skip-count) breakpoints: when a matcher matches, its per-matcher hit counter is incremented (atomically, via BreakpointMatcher.shouldPause()). If the matcher is configured with a skipCount and this hit still falls within the skip window, the hit is recorded but the matcher does NOT pause — findMatch treats it as the winning match and returns null (do not pause) rather than falling through to a later matcher. This preserves first-match semantics: the first matcher to match a request "owns" the decision for that hit. A matcher with no skipCount always pauses (legacy behaviour).

      Parameters:
      request - the inbound request to match against
      phase - the phase to check
      Returns:
      the first matching BreakpointMatcher that should pause, or null
    • findResponseMatch

      public BreakpointMatcher findResponseMatch(RequestDefinition request, HttpResponse response, BreakpointPhase phase)
      Response-phase variant of findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase) that additionally evaluates each matcher's optional response-content conditions (status-code range / body regex) against the actual response about to be written.

      Selection semantics:

      • A matcher is considered only if its phases contain phase and its prebuilt request matcher matches request.
      • If the matcher has a response condition that the response does NOT satisfy, it is treated as not applicable and iteration falls through to later matchers (a response condition is part of what the matcher selects, so a non-matching response means this matcher simply does not want this exchange).
      • The first matcher that matches the request AND satisfies its response condition (or has none) owns the decision: its per-matcher hit counter is incremented and it pauses only if it falls outside any configured skip window — identical to findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase).

      Matchers with no response condition behave exactly as in findMatch(org.mockserver.model.RequestDefinition, org.mockserver.mock.breakpoint.BreakpointPhase). This method is safe to call on the data plane (no allocation beyond the matcher's own logic and the condition evaluation).

      Parameters:
      request - the inbound request to match against
      response - the response about to be written to the downstream client
      phase - the phase to check (typically BreakpointPhase.RESPONSE)
      Returns:
      the first matching BreakpointMatcher that should pause, or null
    • remove

      public boolean remove(String id)
      Removes a breakpoint by id.
      Returns:
      true if the breakpoint was found and removed
    • removeByClientId

      public int removeByClientId(String clientId)
      Removes all breakpoints owned by the given callback client. Called when a WebSocket client disconnects so its breakpoints are cleaned up.
      Parameters:
      clientId - the client id whose breakpoints should be removed
      Returns:
      the number of breakpoints removed
    • clear

      public void clear()
      Clears all registered breakpoints.
    • entries

      public List<BreakpointMatcher> entries()
      Returns a snapshot of all registered breakpoints in registration order.
    • size

      public int size()
      Number of currently registered breakpoints.