= Keeping State in Extensions

Usually, an extension is instantiated only once. So the question becomes relevant: How do
you keep the state from one invocation of an extension to the next? The
`{ExtensionContext}` API provides a `{ExtensionContext_Store}` exactly for this purpose.
Extensions may put values into a store for later retrieval.

TIP: See the `xref:extensions/test-lifecycle-callbacks.adoc#timing-extension[TimingExtension]` for an
example of using the `Store` with a method-level scope.

.The `ExtensionContext` and `Store` hierarchy
image::extensions_StoreHierarchy.svg[alt=UML diagram,role=text-center]

As illustrated by the diagram above, stores are hierarchical in nature. When looking up a
value, if no value is stored in the current `ExtensionContext` for the supplied key, the
stores of the context's ancestors will be queried for a value with the same key in the
`Namespace` used to create this store. The root `ExtensionContext` represents the engine
level so its `Store` may be used to store or cache values that are used by multiple test
classes or extension. The `{ExtensionContext_StoreScope}` enum allows to go beyond even
that and access the stores on the level of the current `{LauncherExecutionRequest}` or
`{LauncherSession}` which can be used to share data across test engines or inject data
from a registered
xref:advanced-topics/launcher-api.adoc#launcher-session-listeners-custom[`LauncherSessionListener`],
respectively. Please consult the Javadoc of `{ExtensionContext}`,
`{ExtensionContext_Store}`, and `{ExtensionContext_StoreScope}` for details.

[[support]]
[NOTE]
.Resource management via `_AutoCloseable_`
====
An extension context store is bound to its extension context lifecycle. When an extension
context lifecycle ends it closes its associated store.

All stored values that are instances of `AutoCloseable` are notified by an invocation of
their `close()` method in the inverse order they were added in (unless the
`junit.jupiter.extensions.store.close.autocloseable.enabled`
xref:running-tests/configuration-parameters.adoc[configuration parameter] is set to `false`).

Versions prior to 5.13 only supported `CloseableResource`, which is deprecated but still
available for backward compatibility.
====

An example implementation of `AutoCloseable` is shown below, using an `HttpServer`
resource.

.`_HttpServer_` resource implementing `_AutoCloseable_`
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/extensions/HttpServerResource.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/extensions/HttpServerResource.kt[tags=user_guide]
----
--
====

This resource can then be stored in the desired `ExtensionContext`. It may be stored at
class or method level, if desired, but this may add unnecessary overhead for this type of
resource. For this example it might be prudent to store it at root level and instantiate
it lazily to ensure it's only created once per test run and reused across different test
classes and methods.

.Lazily storing in root context with `_Store.computeIfAbsent_`
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/extensions/HttpServerExtension.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/extensions/HttpServerExtension.kt[tags=user_guide]
----
--
====

.A test case using the `_HttpServerExtension_`
[tabs]
====
Java::
+
--
[source,java,indent=0]
----
include::example$java/example/HttpServerDemo.java[tags=user_guide]
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
include::example$kotlin/example/kotlin/HttpServerDemo.kt[tags=user_guide]
----
--
====

[[migration]]
[TIP]
.Migration Note for Resource Cleanup
======
The framework automatically closes resources stored in the `ExtensionContext.Store` that
implement `AutoCloseable`. In versions prior to 5.13, only resources implementing
`Store.CloseableResource` were automatically closed.

If you're developing an extension that needs to support both JUnit Jupiter 5.13+ and
earlier versions and your extension stores resources that need to be cleaned up, you
should implement both interfaces:

[tabs]
====
Java::
+
--
[source,java,indent=0]
----
public class MyResource implements Store.CloseableResource, AutoCloseable {
    @Override
    public void close() throws Exception {
        // Resource cleanup code
    }
}
----
--

Kotlin::
+
--
[source,kotlin,indent=0]
----
class MyResource : Store.CloseableResource, AutoCloseable {
    override fun close() {
        // Resource cleanup code
    }
}
----
--
====

This ensures that your resource will be properly closed regardless of which JUnit Jupiter
version is being used.
======
