Skip to content

Application lifecycle and physical drain

A managed deployment separates construction from admission. Dependencies, configuration, policies and generated adapters must be valid before a service becomes available to callers.

@J7mComponent
public final class CatalogLifecycle {
    @Initialize public void initialize() { /* prepare application state */ }
    @Startup public void start() { /* finish startup */ }
    @ReadinessCheck public boolean ready() { return true; }
    @Drain public void drain() { /* stop accepting application-owned work */ }
    @Shutdown public void stop() { /* release resources after drain */ }
}

This is a callback-shape fragment, not a complete deployment. The managed host performs the transition ordering and validates callback shapes before construction. A manually created new CatalogLifecycle() does not cause these methods to execute automatically.

Health and readiness answer different questions

A health check reports whether the component can function. Readiness governs whether new application work should be admitted. Avoid expensive checks, mutable business effects or disclosure of secrets in either callback. Host policy still decides how a check affects publication and administration.

Logical completion is not physical exit

A caller may time out while Java code or tracked child work is still running. J7M retains the owned CALL, component resources, permits and application class loader until physical work and finalizers finish. Cancelling a future does not prove that an external effect was undone.

When drain cannot finish within its budget, treat the application as draining rather than stopped. Releasing its class loader or running final shutdown while a callback still uses it would break ownership. Uncooperative code can therefore retain bounded capacity; the middleware does not claim to force arbitrary Java to terminate safely.

Explicit lifecycle

When embedding without lifecycle annotations, the host performs the same responsibility explicitly: prepare dependencies, publish only after readiness, stop admission, await real completion, then close exports and owned resources. Use structured try/finally or AutoCloseable ownership rather than relying on JVM shutdown hooks.

Drive lifecycle from an embedded host

The following application fragment uses the GreetingComponent and GreetingFormatter included below. The generated index classes come from compiling these components with J7M's annotation processor. ManagedLifecycle is in org.j7m.middleware.application.api.

try (var container = ManagedContainer.activate(List.of(
        new GreetingFormatter__J7mComponentIndex(),
        new GreetingComponent__J7mComponentIndex()))) {
    container.lifecycle(ManagedLifecycle.STARTUP);
    try {
        var greetings = container.get(GreetingComponent.class, "", List.of());
        System.out.println(greetings.greet("Ada"));
    } finally {
        container.lifecycle(ManagedLifecycle.DRAIN);
        container.lifecycle(ManagedLifecycle.SHUTDOWN);
    }
}
GreetingFormatter.java
/*
 * BSD 4-Clause License
 *
 * Copyright (c) 2026, Leo Galambos and the Egothor team
 * Website of the Egothor team: https://www.egothor.org
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 * software must display the following acknowledgement:
 *
 * This product includes software developed by Leo Galambos and the Egothor
 * team (https://www.egothor.org).
 *
 * 4. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.j7m.documentation;

import org.j7m.middleware.annotations.J7mComponent;

/**
 * Application-owned formatting dependency used by the generated injection example.
 */
@J7mComponent
public final class GreetingFormatter {
    /**
     * Creates the stateless formatter.
     */
    public GreetingFormatter() { }

    /**
     * Formats a greeting without remote or persistent effects.
     * @param name nonnull recipient name
     * @return greeting addressed to the recipient
     */
    public String format(String name) {
        return "Hello, " + name;
    }
}
GreetingComponent.java
/*
 * BSD 4-Clause License
 *
 * Copyright (c) 2026, Leo Galambos and the Egothor team
 * Website of the Egothor team: https://www.egothor.org
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 * software must display the following acknowledgement:
 *
 * This product includes software developed by Leo Galambos and the Egothor
 * team (https://www.egothor.org).
 *
 * 4. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.j7m.documentation;

import org.j7m.middleware.annotations.Inject;
import org.j7m.middleware.annotations.J7mComponent;
import org.j7m.middleware.annotations.Shutdown;
import org.j7m.middleware.annotations.Startup;

/**
 * Constructor-injected component whose lifecycle is driven by its owning host.
 */
@J7mComponent
public final class GreetingComponent {
    private final GreetingFormatter formatter;
    private boolean started;

    /**
     * Creates a component from a graph-validated dependency.
     * @param formatter formatter resolved from the same activation
     */
    @Inject
    public GreetingComponent(GreetingFormatter formatter) {
        this.formatter = formatter;
    }

    /**
     * Opens business admission after dependency construction and initialization.
     */
    @Startup
    public void start() { started = true; }

    /**
     * Produces a greeting while this component has been started.
     * @param name recipient name
     * @return formatted greeting
     * @throws IllegalStateException before startup or after shutdown
     */
    public String greet(String name) {
        if (!started) throw new IllegalStateException("Component is not started");
        return formatter.format(name);
    }

    /**
     * Revokes this component's simple example admission flag.
     */
    @Shutdown
    public void stop() { started = false; }
}

The business method returns Hello, Ada while started and rejects use after shutdown. This small synchronous component has no child work; a hosted asynchronous service additionally needs the host's physical-drain protocol before final shutdown. See deployment lifecycle.