Class ScrollSearchHandler

java.lang.Object
org.codelibs.fess.api.v2.handlers.ScrollSearchHandler

public class ScrollSearchHandler extends Object
Handles the /api/v2/documents/all endpoint — streaming scroll search.

Mirrors v1's SearchApiManager#processScrollSearchRequest but emits NDJSON (application/x-ndjson; charset=UTF-8) where each line is a {"data":{...}} envelope wrapping one filtered document. The wrapper adds a stable "data" key per line so v2 callers can branch on the same field name they get back from the non-streaming /search endpoint without special-casing the scroll path.

Unlike the other v2 handlers this one does not emit a JSON envelope on the success path — the response body is a stream of documents, not a single object. Error paths still go through V2EnvelopeWriter so client SDKs see structured failures in the usual shape.

Wire contract — mid-stream error terminator (MJ-22): When an exception is thrown after at least one NDJSON line has been written, the handler emits a final NDJSON record: {"error":{"code":"internal_error","message":"stream error"}}\n and then flushes. Clients MUST check whether the final line contains an "error" key to distinguish "stream complete" from "server crashed mid-stream". If the final-line write itself fails, the stream terminates without a terminator — this is unavoidable and the client must treat unexpected EOF as an error.

Referer allowlist (MJ-21): v1's SearchApiManager enforced isAcceptedSearchReferer (~line 860) as a browser-driven scraping defence. v2 omits this check deliberately: idempotent GETs carry no side-effects that require Referer gating. CSRF protection covers state-changing endpoints. See SearchHandler for the same rationale.

The handler is stateless; the manager holds a single shared instance and dispatches concurrent requests through it without locking. MAPPER is a static final instance because ObjectMapper is thread-safe after configuration (m-11).

  • Constructor Details

    • ScrollSearchHandler

      public ScrollSearchHandler()
      Default constructor. The handler is stateless and intended to be instantiated once by the API manager and shared across concurrent requests.
  • Method Details

    • handle

      public void handle(jakarta.servlet.http.HttpServletRequest request, jakarta.servlet.http.HttpServletResponse response) throws IOException
      Processes one /api/v2/documents/all request.

      Rejects non-GET methods and feature-disabled cases with V2ErrorCode.INVALID_REQUEST. On the success path the NDJSON content-type is set before the first write so chunked clients see the type at the start of the stream; the type is not reset between lines.

      Parameters:
      request - the incoming HTTP request
      response - the HTTP response to write to
      Throws:
      IOException - if writing the envelope or any NDJSON line fails