File System Plugin
The File System plugin (tika-pipes-file-system) is the most common starting point for Tika Pipes. It provides all four interfaces — fetcher, emitter, iterator, and reporter — backed by the local (or mounted) filesystem.
| Interface | Component name | Class |
|---|---|---|
Fetcher |
|
|
Emitter |
|
|
Iterator |
|
|
Reporter |
|
|
Complete Pipeline Example
The canonical filesystem-to-filesystem integration-test config. FETCHER_BASE_PATH, EMITTER_BASE_PATH and PLUGINS_PATHS are placeholders the test harness substitutes with real paths; EMIT_INTERMEDIATE_RESULTS with the boolean true or false. See Pipes Configuration for what each setting does.
{
"content-handler-factory": {
"basic-content-handler-factory": {
"type": "TEXT",
"writeLimit": -1,
"throwOnWriteLimitReached": true
}
},
"fetchers": {
"fsf": {
"file-system-fetcher": {
"basePath": "FETCHER_BASE_PATH",
"extractFileSystemMetadata": false
}
}
},
"emitters": {
"fse": {
"file-system-emitter": {
"basePath": "EMITTER_BASE_PATH",
"fileExtension": "json",
"onExists": "EXCEPTION"
}
}
},
"pipes-iterator": {
"file-system-pipes-iterator": {
"basePath": "FETCHER_BASE_PATH",
"countTotal": true,
"fetcherId": "fsf",
"emitterId": "fse"
}
},
"pipes": {
"parseMode": "RMETA",
"onParseException": "EMIT",
"numClients": 4,
"emitIntermediateResults": "EMIT_INTERMEDIATE_RESULTS",
"forkedJvmArgs": ["-Xmx512m"],
"emitStrategy": {
"type": "DYNAMIC",
"thresholdBytes": 1000000
}
},
"auto-detect-parser": {
"throwOnZeroBytes": false
},
"parse-context": {
"mock-digester-factory": {},
"timeout-limits": {
"progressTimeoutMillis": 5000
}
},
"plugin-roots": "PLUGINS_PATHS"
}
File System Fetcher (file-system-fetcher)
Reads files from a local or mounted filesystem. Fetch keys are resolved relative to basePath.
{
"fetchers": {
"fsf": {
"file-system-fetcher": {
"basePath": "/data/input",
"extractFileSystemMetadata": true
}
}
}
}
The outer key (fsf) is the fetcher ID — referenced by pipesIterator.fetcherId elsewhere in the config.
Configuration
| Field | Default | Description |
|---|---|---|
|
none |
Base directory for fetch operations. Fetch keys are resolved relative to this path and must stay inside it. Omitting it requires |
|
|
When |
|
|
Permission to run without a |
File System Emitter (file-system-emitter)
Writes parsed results as files under basePath. The relative output path is derived from the emit key of each FetchEmitTuple.
{
"emitters": {
"fse": {
"file-system-emitter": {
"basePath": "/data/output",
"fileExtension": "json",
"onExists": "EXCEPTION",
"prettyPrint": false
}
}
}
}
Configuration
| Field | Default | Description |
|---|---|---|
|
none |
Base output directory. Emit keys are resolved relative to this path and must stay inside it. Omitting it requires |
|
|
Permission to run without a |
|
none |
Extension appended to each output file; omitted entirely when unset. Applied on both output paths, so under |
|
|
Behavior when the output file already exists: |
|
|
Pretty-print JSON output. Has no effect in |
File System Iterator (file-system-pipes-iterator)
Recursively walks a directory tree, emitting one FetchEmitTuple per file found.
{
"pipes-iterator": {
"file-system-pipes-iterator": {
"basePath": "/data/input",
"countTotal": true,
"fetcherId": "fsf",
"emitterId": "fse"
}
}
}
Configuration
In addition to the required fetcherId / emitterId (see Wiring an Iterator):
| Field | Default | Description |
|---|---|---|
|
required |
Root directory to walk. |
|
|
If |
Notes
-
Walk order is filesystem-dependent and not guaranteed stable across runs.
-
The relative path of each file (from
basePath) becomes the fetch key, and by default also the emit key. -
Symbolic links are not followed: the walk runs without
FOLLOW_LINKS, so a symlinked directory is emitted as a single entry rather than descended into.
File System Reporter (file-system-reporter)
Maintains a JSON status file that summarizes pipeline progress. The reporter writes the file periodically on a background thread; per-record report() calls only update in-memory counters.
{
"pipes-reporters": {
"file-system-reporter": {
"statusFile": "/var/log/tika/status.json",
"reportUpdateMs": 1000
}
}
}
pipes-reporters accepts multiple reporters keyed by component name — see Pipes Reporters for how multiple reporters compose.
Configuration
| Field | Default | Description |
|---|---|---|
|
required |
Path of the JSON status file. Absolute paths are written as given; relative paths resolve against the JVM’s working directory at startup. Missing parent directories are created at startup. Always include a parent component (e.g., |
|
|
Interval in milliseconds between status-file writes. Typical values: |
Status file schema
The reporter serializes an AsyncStatus object to JSON, containing:
-
started— ISO-8601 timestamp of when the reporter was constructed. -
lastUpdate— ISO-8601 timestamp of the most recent write. -
asyncStatus— current pipeline phase (STARTED,COMPLETED,CRASHED). -
statusCounts— map ofPipesResult.RESULT_STATUSto count (e.g.,PARSE_SUCCESS,PARSE_SUCCESS_WITH_EXCEPTION,TIMEOUT,OOM,EMIT_SUCCESS,EMIT_EXCEPTION). -
totalCountResult— total documents discovered by the iterator and whether the enumeration is complete. -
crashMessage— empty string under normal operation; populated with a stack trace on fatal pipeline failure.
The file is rewritten in full on each tick, not appended.
The write is not atomic — the reporter opens the target path with Files.newBufferedWriter, truncates, and streams the JSON. A watcher reading concurrently with a write can observe a truncated or partial document. Have the watcher treat a parse error as "stale read, try again on the next poll" rather than as a real error.
|
Live status for watching applications
The reporter is designed to support external "watchers" — UIs, dashboards, or monitoring scripts that poll the status file to display pipeline progress. To use it that way, set reportUpdateMs to match your desired refresh rate:
"reportUpdateMs": 250
The watcher polls statusFile on its own interval and reads the most recent snapshot. Each tick rewrites the file in full, so successive snapshots are always coherent — but because the write is not atomic, a watcher reading mid-write can see a truncated document. Tolerate JSON parse errors as transient and retry on the next poll (see the NOTE under Status file schema).
This pattern is used by tika-gui-v2 to drive its progress UI: the GUI starts a pipeline subprocess, points the reporter at a temp file, and polls that file every few hundred milliseconds.
Tradeoffs:
-
Smaller
reportUpdateMsvalues mean more disk writes. On a fast SSD this is negligible, but on a slow disk (or NFS) the writer thread can become a bottleneck. -
The reporter thread sleeps between writes, so the worst-case staleness of the file is
reportUpdateMsmilliseconds plus serialization time. -
Per-record
report()calls are cheap (counter increment only). The cost of "watching" is bounded by the periodic write, not by document throughput.
Security Notes
-
basePathis the sandbox boundary, and it is the only one. WithbasePathset, the fetcher and emitter reject any key that resolves outside it, including absolute paths and../traversal.allowAbsolutePathshas no effect in this state. -
Without
basePaththere is no containment at all. The key is used as a raw absolute path, and the containment checks are skipped entirely.allowAbsolutePaths=trueis how you assert that you intend this; it is a switch between two states, not a dial that loosensbasePath. For the fetcher this means any file the process can read; for the emitter, any file it can write. Use it only when fetch/emit keys come from a fully trusted source and access to the service is restricted by other means. -
Symlink containment differs between fetcher and emitter. The fetcher re-checks with
toRealPath(), so a symlink underbasePathpointing outside it is rejected. The emitter does not: it checks only the normalized path, so a symlink already present under itsbasePathcan be written through. Do not rely on symlinks being contained on the emit side. -
Output directories are created automatically. The emitter creates intermediate directories as needed. Make sure the process’s umask is appropriate for the data being written.