Office Managers¶
This page explains what an Office Manager is in the JODConverter ecosystem and how it fits into conversions.
What is an Office Manager?¶
In JODConverter, an Office Manager is the component responsible for starting, supervising, and using office processes (LibreOffice or OpenOffice) to execute OfficeTasks such as document conversions. It provides a simple lifecycle and a thread-safe execution API:
- start(): boots the underlying office process(es) and gets them ready to accept tasks.
- execute(OfficeTask): submits a task and blocks until it completes.
- stop(): shuts down the manager and its office process(es). After
stop(), a manager cannot be restarted.
See the interface definition: org.jodconverter.core.office.OfficeManager.
Why do you need one?¶
Converters (e.g., LocalConverter or RemoteConverter) do not start OOo themselves. They delegate
to an Office Manager which maintains the connection(s) to office processes, enforces timeouts, queues tasks, and
recovers from failures.
Without an Office Manager, there’s no running office backend to perform conversions.
Manager types¶
JODConverter ships with different Office Manager implementations depending on how and where OOo runs:
- LocalOfficeManager: Starts and manages one or more local office processes on the same machine as your application. Best for typical server-side use when OOo is installed locally. See LocalOfficeManager for all configuration options.
- AttachedOfficeManager: Attaches to office processes you start yourself, on the same machine or on another one
(you manage the process lifecycle; JODConverter connects over UNO and reconnects when a process is restarted).
Formerly
ExternalOfficeManager. See AttachedOfficeManager for all configuration options. - RemoteOfficeManager: Connects to a remote LibreOffice Online (LOOL/Collabora Online) server through HTTP/WebSocket. The office process lifecycle is remote; the manager controls the connection pool. See RemoteOfficeManager for all configuration options.
Internally, pool-capable managers derive from an abstract pool (AbstractOfficeWorkerPool) that dispatches the tasks
to a pool of workers, one per office process or connection (via multiple ports or pipes), for concurrency and
resilience. The tasks wait in a single queue, and a worker only takes a task when its office process is ready: while a
process is starting or restarting (after its maximum number of tasks, a lost connection, a crash or a timed-out task),
the tasks go to the other processes. taskQueueCapacity can bound the queue so that an overloaded application fails
fast, and two timeouts apply to a task: taskQueueTimeout, from its submission until a worker takes it, and
taskExecutionTimeout, from the moment a worker starts it.
The pool can be observed: getStatus() returns a snapshot with the state of each worker (STARTING, READY, BUSY,
RESTARTING or STOPPED), the tasks it executed since it was last made ready, its restarts and its failed start
attempts in a row, plus the number of tasks waiting in the queue and the number of times a task was executed again after its worker was lost (see taskRetries). With the Spring Boot starter and Spring Boot Actuator
on the classpath, the jodconverter health indicator reports these details for every office manager bean, and is down
when a manager has no worker able to execute tasks (management.health.jodconverter.enabled=false disables it).
With Micrometer on the classpath too, which Spring Boot Actuator brings, the starter also exposes the same numbers as meters, read from getStatus() each time they are collected. Each meter has a name tag, the name of the office manager bean (localOfficeManager, attachedOfficeManager or remoteOfficeManager):
| Meter | Type | What it measures |
|---|---|---|
jodconverter.queue.size |
Gauge | The tasks waiting in the queue for a worker. |
jodconverter.tasks.retries |
Counter | The times a task was executed again after its worker was lost; stays at zero without taskRetries. |
jodconverter.workers |
Gauge | The workers in a state, given by the state tag: starting, ready, busy, restarting or stopped. |
jodconverter.workers.tasks |
Gauge | The tasks executed by the workers since each was last made ready. |
jodconverter.workers.restarts |
Counter | The restarts of the workers since the manager was started. |
jodconverter.workers.start.failures |
Gauge | The start attempts in a row that failed, for all the workers; above zero, an office process does not come back. |
A queue that keeps growing while every worker is busy means the pool is too small for the load, and a restart counter that climbs faster than maxTasksPerProcess explains is the sign of crashes or of timed-out tasks. jodconverter.metrics.enabled=false disables the meters.
Describing the office¶
OfficeInfoTask asks the office behind a local or an attached manager what it is: its product name, its version, and the filters it has to load and to store documents. No document is loaded.
OfficeInfo info = OfficeInfoTask.query(officeManager);
info.productName(); // LibreOffice
info.version(); // 25.2.7.2
info.exportFilters(); // writer_pdf_Export, calc_pdf_Export, MS Word 97...
Each OfficeFilterInfo gives the name of the filter (the value of the FilterName store property of a custom format), the name the office shows for it, the service of the documents it applies to, the media type and the extensions of its file type, and whether it loads documents, stores them, or both. It answers "which office is this application really talking to, and can it write that format?" at startup or behind a support endpoint.
The task asks the office for each of its filters, a few hundred calls: execute it once and keep the result, not for each conversion. It is not available with a RemoteOfficeManager.
Typical usage patterns¶
1) Install a global (default) manager.
- Installing a manager in the
InstalledOfficeManagerHolderlets converter builders use it automatically when you don't specify any office manager.
Java example:
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.core.office.OfficeUtils;
import org.jodconverter.local.LocalConverter;
import org.jodconverter.local.office.LocalOfficeManager;
public class Example {
public static void main(String[] args) throws OfficeException {
// Build and install a LocalOfficeManager as the global default
LocalOfficeManager officeManager = LocalOfficeManager.install();
try {
officeManager.start();
// Now LocalConverter.make() will use the installed manager by default
LocalConverter
.make()
.convert(new java.io.File("in.docx"))
.to(new java.io.File("out.pdf"))
.execute();
} finally {
OfficeUtils.stopQuietly(officeManager);
}
}
}
2) Pass a manager explicitly to a converter.
import org.jodconverter.core.office.OfficeException;
import org.jodconverter.core.office.OfficeUtils;
import org.jodconverter.core.office.OfficeManager;
import org.jodconverter.local.LocalConverter;
import org.jodconverter.local.office.LocalOfficeManager;
OfficeManager officeManager = LocalOfficeManager.builder().build();
try {
officeManager.start();
LocalConverter
.builder()
.officeManager(officeManager)
.build()
.convert(new java.io.File("in.docx"))
.to(new java.io.File("out.pdf"))
.execute();
} finally {
OfficeUtils.stopQuietly(officeManager);
}
3) Attach to office processes you start yourself (AttachedOfficeManager).
If you start LibreOffice yourself with a known accept string, use AttachedOfficeManager. See
AttachedOfficeManager for details.
4) Use a remote LibreOffice Online server (RemoteOfficeManager).
When targeting LO Online/Collabora Online, create a RemoteOfficeManager and pass it to a RemoteConverter.
See RemoteOfficeManager.
Lifecycle and threading¶
- Start before use: Always call
start()before invokingexecute()through a converter. - Stop on shutdown: Call
stop()when your application shuts down. OfficeUtils.stopQuietly(...) is provided for convenience in finally blocks. - Not restartable: Once stopped, a given manager instance cannot be restarted; create a new instance if needed.
- Thread-safe queueing: Managers queue and dispatch tasks to their office processes. Timeouts like
taskExecutionTimeoutandtaskQueueTimeoutprotect against slow or stuck tasks (see LocalOfficeManager configuration page for more details).
Best practices¶
- One manager per application: Create one
OfficeManagerand reuse it across conversions. Avoid creating a manager per request. - Start early: Start the manager during application boot (e.g., in a servlet context listener or Spring Boot lifecycle) and stop it with a shutdown hook.
- Tune for throughput: For concurrent workloads, configure multiple ports/pipes so the manager can spawn multiple office processes.
- Mitigate leaks: Keep
maxTasksPerProcessat a reasonable value so office processes are recycled periodically. - Use the holder wisely: install() sets the
InstalledOfficeManagerHolder; this is convenient for libraries and reduces boilerplate.
Related APIs¶
OfficeManager(core): lifecycle and execute contract.InstalledOfficeManagerHolder(core): global singleton used by converter builders when no manager is provided.LocalOfficeManager(local): starts and manages local OOo processes.ExternalOfficeManager(local): connects to an already running local office process you manage externally.RemoteOfficeManager(remote): connects to LibreOffice Online / Collabora Online.
For in-depth configuration of each manager type, refer to:
Whenever OpenOffice.org (OOo for short) is mentioned, this can generally be interpreted to include any office suite derived from OOo such as Apache OpenOffice and LibreOffice.